comparison packages/devs/eth/phy/current/src/eth_phy.c @ 1178:0832585993c1

New abstractions to handle device specifics
author gthomas
date Tue, 26 Aug 2003 17:54:00 +0000
parents 719dd033d039
children 0418d60dd8fb
comparison
equal deleted inserted replaced
1177:2af5a454cc1f 1178:0832585993c1
56 #include <cyg/infra/diag.h> 56 #include <cyg/infra/diag.h>
57 57
58 #include <cyg/hal/hal_arch.h> 58 #include <cyg/hal/hal_arch.h>
59 #include <cyg/hal/drv_api.h> 59 #include <cyg/hal/drv_api.h>
60 #include <cyg/hal/hal_if.h> 60 #include <cyg/hal/hal_if.h>
61 #include <cyg/hal/hal_tables.h>
61 62
62 #include <cyg/io/eth_phy.h> 63 #include <cyg/io/eth_phy.h>
64 #include <cyg/io/eth_phy_dev.h>
65
66 // Define table boundaries
67 CYG_HAL_TABLE_BEGIN( __ETH_PHY_TAB__, _eth_phy_devs );
68 CYG_HAL_TABLE_END( __ETH_PHY_TAB_END__, _eth_phy_devs );
69 extern struct _eth_phy_dev_entry __ETH_PHY_TAB__[], __ETH_PHY_TAB_END__;
63 70
64 // MII interface 71 // MII interface
65 #define MII_Start 0x40000000 72 #define MII_Start 0x40000000
66 #define MII_Read 0x20000000 73 #define MII_Read 0x20000000
67 #define MII_Write 0x10000000 74 #define MII_Write 0x10000000
69 #define MII_Phy(phy) (phy << 23) 76 #define MII_Phy(phy) (phy << 23)
70 #define MII_Reg(reg) (reg << 18) 77 #define MII_Reg(reg) (reg << 18)
71 #define MII_TA 0x00020000 78 #define MII_TA 0x00020000
72 79
73 // 80 //
74 // PHY unit access (via MII channel) 81 // PHY unit access (via MII channel, using bit-level operations)
75 // 82 //
76 83
77 static cyg_uint32 84 static cyg_uint32
78 phy_cmd(eth_phy_access_t *f, cyg_uint32 cmd) 85 phy_cmd(eth_phy_access_t *f, cyg_uint32 cmd)
79 { 86 {
80 cyg_uint32 retval; 87 cyg_uint32 retval;
81 int i, off; 88 int i, off;
82 bool is_read = ((cmd & MII_Cmd) == MII_Read); 89 bool is_read = ((cmd & MII_Cmd) == MII_Read);
83 90
84 // Set both bits as output 91 // Set both bits as output
85 (f->set_dir)(1); 92 (f->ops.bit_level_ops.set_dir)(1);
86 93
87 // Preamble 94 // Preamble
88 for (i = 0; i < 32; i++) { 95 for (i = 0; i < 32; i++) {
89 (f->set_clock)(0); 96 (f->ops.bit_level_ops.set_clock)(0);
90 (f->set_data)(1); 97 (f->ops.bit_level_ops.set_data)(1);
91 CYGACC_CALL_IF_DELAY_US(1); 98 CYGACC_CALL_IF_DELAY_US(1);
92 (f->set_clock)(1); 99 (f->ops.bit_level_ops.set_clock)(1);
93 CYGACC_CALL_IF_DELAY_US(1); 100 CYGACC_CALL_IF_DELAY_US(1);
94 } 101 }
95 102
96 // Command/data 103 // Command/data
97 for (i = 0, off = 31; i < (is_read ? 14 : 32); i++, --off) { 104 for (i = 0, off = 31; i < (is_read ? 14 : 32); i++, --off) {
98 (f->set_clock)(0); 105 (f->ops.bit_level_ops.set_clock)(0);
99 (f->set_data)((cmd >> off) & 0x00000001); 106 (f->ops.bit_level_ops.set_data)((cmd >> off) & 0x00000001);
100 CYGACC_CALL_IF_DELAY_US(1); 107 CYGACC_CALL_IF_DELAY_US(1);
101 (f->set_clock)(1); 108 (f->ops.bit_level_ops.set_clock)(1);
102 CYGACC_CALL_IF_DELAY_US(1); 109 CYGACC_CALL_IF_DELAY_US(1);
103 } 110 }
104 111
105 retval = cmd; 112 retval = cmd;
106 113
107 // If read, fetch data register 114 // If read, fetch data register
108 if (is_read) { 115 if (is_read) {
109 retval >>= 16; 116 retval >>= 16;
110 117
111 (f->set_clock)(0); 118 (f->ops.bit_level_ops.set_clock)(0);
112 (f->set_dir)(0); 119 (f->ops.bit_level_ops.set_dir)(0);
113 CYGACC_CALL_IF_DELAY_US(1); 120 CYGACC_CALL_IF_DELAY_US(1);
114 (f->set_clock)(1); 121 (f->ops.bit_level_ops.set_clock)(1);
115 CYGACC_CALL_IF_DELAY_US(1); 122 CYGACC_CALL_IF_DELAY_US(1);
116 (f->set_clock)(0); 123 (f->ops.bit_level_ops.set_clock)(0);
117 CYGACC_CALL_IF_DELAY_US(1); 124 CYGACC_CALL_IF_DELAY_US(1);
118 125
119 for (i = 0, off = 15; i < 16; i++, off--) { 126 for (i = 0, off = 15; i < 16; i++, off--) {
120 (f->set_clock)(1); 127 (f->ops.bit_level_ops.set_clock)(1);
121 retval <<= 1; 128 retval <<= 1;
122 retval |= (f->get_data)(); 129 retval |= (f->ops.bit_level_ops.get_data)();
123 CYGACC_CALL_IF_DELAY_US(1); 130 CYGACC_CALL_IF_DELAY_US(1);
124 (f->set_clock)(0); 131 (f->ops.bit_level_ops.set_clock)(0);
125 CYGACC_CALL_IF_DELAY_US(1); 132 CYGACC_CALL_IF_DELAY_US(1);
126 } 133 }
127 } 134 }
128 135
129 // Set both bits as output 136 // Set both bits as output
130 (f->set_dir)(1); 137 (f->ops.bit_level_ops.set_dir)(1);
131 138
132 // Postamble 139 // Postamble
133 for (i = 0; i < 32; i++) { 140 for (i = 0; i < 32; i++) {
134 (f->set_clock)(0); 141 (f->ops.bit_level_ops.set_clock)(0);
135 (f->set_data)(1); 142 (f->ops.bit_level_ops.set_data)(1);
136 CYGACC_CALL_IF_DELAY_US(1); 143 CYGACC_CALL_IF_DELAY_US(1);
137 (f->set_clock)(1); 144 (f->ops.bit_level_ops.set_clock)(1);
138 CYGACC_CALL_IF_DELAY_US(1); 145 CYGACC_CALL_IF_DELAY_US(1);
139 } 146 }
140 147
141 return retval; 148 return retval;
142 } 149 }
143 150
151 externC bool
152 _eth_phy_init(eth_phy_access_t *f)
153 {
154 int addr;
155 unsigned short state;
156 unsigned long id;
157 struct _eth_phy_dev_entry *dev;
158
159 if (f->init_done) return true;
160 (f->init)();
161 // Scan to determine PHY address
162 f->init_done = true;
163 for (addr = 0; addr < 0x20; addr++) {
164 if (_eth_phy_read(f, PHY_ID1, addr, &state)) {
165 id = state << 16;
166 if (_eth_phy_read(f, PHY_ID2, addr, &state)) {
167 id |= state;
168 f->phy_addr = addr;
169 for (dev = __ETH_PHY_TAB__; dev != &__ETH_PHY_TAB_END__; dev++) {
170 if (dev->id == id) {
171 diag_printf("PHY: %s\n", dev->name);
172 f->dev = dev;
173 return true;
174 }
175 }
176 diag_printf("Unsupported PHY device - id: %x\n", id);
177 break; // Can't handle this PHY
178 }
179 }
180 }
181 f->init_done = false;
182 return false;
183 }
184
144 externC void 185 externC void
145 _eth_phy_init(eth_phy_access_t *f) 186 _eth_phy_reset(eth_phy_access_t *f)
146 { 187 {
188 if (!f->init_done) {
189 diag_printf("PHY reset without init on PHY: %x\n", f);
190 return;
191 }
147 (f->init)(); 192 (f->init)();
148 } 193 }
149 194
150 externC void 195 externC void
151 _eth_phy_write(eth_phy_access_t *f, int reg, int addr, unsigned short data) 196 _eth_phy_write(eth_phy_access_t *f, int reg, int addr, unsigned short data)
152 { 197 {
153 phy_cmd(f, MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data); 198 if (!f->init_done) {
199 diag_printf("PHY write without init on PHY: %x\n", f);
200 return;
201 }
202 if (f->ops_type == PHY_BIT_LEVEL_ACCESS_TYPE) {
203 phy_cmd(f, MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data);
204 } else {
205 (f->ops.reg_level_ops.put_reg)(reg, addr, data);
206 }
154 } 207 }
155 208
156 externC bool 209 externC bool
157 _eth_phy_read(eth_phy_access_t *f, int reg, int addr, unsigned short *val) 210 _eth_phy_read(eth_phy_access_t *f, int reg, int addr, unsigned short *val)
158 { 211 {
159 cyg_uint32 ret; 212 cyg_uint32 ret;
160 213
161 ret = phy_cmd(f, MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA); 214 if (!f->init_done) {
162 *val = ret; 215 diag_printf("PHY read without init on PHY: %x\n", f);
163 return true; 216 return false;
164 } 217 }
165 218 if (f->ops_type == PHY_BIT_LEVEL_ACCESS_TYPE) {
166 externC void _eth_phy_init(eth_phy_access_t *f); 219 ret = phy_cmd(f, MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA);
167 externC void _eth_phy_write(eth_phy_access_t *f, int reg, int unit, unsigned short data); 220 *val = ret;
168 externC bool _eth_phy_read(eth_phy_access_t *f, int reg, int unit, unsigned short *val); 221 return true;
222 } else {
223 return (f->ops.reg_level_ops.get_reg)(reg, addr, val);
224 }
225 }
226
227 externC int
228 _eth_phy_cfg(eth_phy_access_t *f, int mode)
229 {
230 int phy_timeout = 5*1000; // Wait 5 seconds max for link to clear
231 bool phy_ok;
232 unsigned short reset_mode, phy_state;
233 int i;
234
235 if (!f->init_done) {
236 diag_printf("PHY config without init on PHY: %x\n", f);
237 return;
238 }
239
240 // Reset PHY (transceiver)
241 phy_ok = false;
242 _eth_phy_reset(f);
243
244 _eth_phy_write(f, PHY_BMCR, f->phy_addr, PHY_BMCR_RESET);
245 for (i = 0; i < 5*100; i++) {
246 phy_ok = _eth_phy_read(f, PHY_BMCR, f->phy_addr, &phy_state);
247 diag_printf("PHY: %x\n", phy_state);
248 if (phy_ok && !(phy_state & PHY_BMCR_RESET)) break;
249 CYGACC_CALL_IF_DELAY_US(10000); // 10ms
250 }
251 if (!phy_ok || (phy_state & PHY_BMCR_RESET)) {
252 diag_printf("PPC405: Can't get PHY unit to soft reset: %x\n", phy_state);
253 return 0;
254 }
255
256 reset_mode = PHY_BMCR_RESTART | PHY_BMCR_AUTO_NEG;
257 _eth_phy_write(f, PHY_BMCR, f->phy_addr, reset_mode);
258 while (phy_timeout-- >= 0) {
259 phy_ok = _eth_phy_read(f, PHY_BMSR, f->phy_addr, &phy_state);
260 if (phy_ok && (phy_state & PHY_BMSR_AUTO_NEG)) {
261 break;
262 } else {
263 CYGACC_CALL_IF_DELAY_US(10000); // 10ms
264 }
265 }
266 if (phy_timeout <= 0) {
267 diag_printf("** PPC405 Warning: PHY LINK UP failed: %04x\n", phy_state);
268 return 0;
269 }
270
271 return _eth_phy_state(f);
272 }
273
274 externC int
275 _eth_phy_state(eth_phy_access_t *f)
276 {
277 int state = 0;
278
279 if (!f->init_done) {
280 diag_printf("PHY state without init on PHY: %x\n", f);
281 return 0;
282 }
283 if ((f->dev->stat)(f, &state)) {
284 return state;
285 } else {
286 return 0;
287 }
288 return state;
289 }