Mercurial > ecos
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 } |
