esp_eth_phy_dm9051.c
1 // Copyright 2019 Espressif Systems (Shanghai) PTE LTD 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 #include <string.h> 15 #include <stdlib.h> 16 #include <sys/cdefs.h> 17 #include "esp_log.h" 18 #include "esp_eth.h" 19 #include "eth_phy_regs_struct.h" 20 #include "freertos/FreeRTOS.h" 21 #include "freertos/task.h" 22 #include "driver/gpio.h" 23 #include "esp_rom_gpio.h" 24 #include "esp_rom_sys.h" 25 26 static const char *TAG = "dm9051"; 27 #define PHY_CHECK(a, str, goto_tag, ...) \ 28 do \ 29 { \ 30 if (!(a)) \ 31 { \ 32 ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ 33 goto goto_tag; \ 34 } \ 35 } while (0) 36 37 /***************Vendor Specific Register***************/ 38 39 /** 40 * @brief DSCR(DAVICOM Specified Configuration Register) 41 * 42 */ 43 typedef union { 44 struct { 45 uint32_t reserved1 : 1; /* Reserved */ 46 uint32_t sleep : 1; /* Set 1 to enable PHY into sleep mode */ 47 uint32_t mfpsc : 1; /* MII frame preamble suppression control bit */ 48 uint32_t smrst : 1; /* Set 1 to reset all state machines of PHY */ 49 uint32_t rpdctr_en : 1; /* Set 1 to enable automatic reduced power down */ 50 uint32_t reserved2 : 2; /* Reserved */ 51 uint32_t flink100 : 1; /* Force Good Link in 100Mbps */ 52 uint32_t reserved3 : 2; /* Reserved */ 53 uint32_t tx_fx : 1; /* 100BASE-TX or FX Mode Control */ 54 uint32_t reserved4 : 1; /* Reserved */ 55 uint32_t bp_adpok : 1; /* BYPASS ADPOK */ 56 uint32_t bp_align : 1; /* Bypass Symbol Alignment Function */ 57 uint32_t bp_scr : 1; /* Bypass Scrambler/Descrambler Function */ 58 uint32_t bp_4b5b : 1; /* Bypass 4B5B Encoding and 5B4B Decoding */ 59 }; 60 uint32_t val; 61 } dscr_reg_t; 62 #define ETH_PHY_DSCR_REG_ADDR (0x10) 63 64 /** 65 * @brief DSCSR(DAVICOM Specified Configuration and Status Register) 66 * 67 */ 68 typedef union { 69 struct { 70 uint32_t anmb : 4; /* Auto-Negotiation Monitor Bits */ 71 uint32_t phy_addr : 5; /* PHY Address */ 72 uint32_t reserved : 3; /* Reserved */ 73 uint32_t hdx10 : 1; /* 10M Half-Duplex Operation Mode */ 74 uint32_t fdx10 : 1; /* 10M Full-Duplex Operation Mode */ 75 uint32_t hdx100 : 1; /* 100M Half-Duplex Operation Mode */ 76 uint32_t fdx100 : 1; /* 100M Full-Duplex Operation Mode */ 77 }; 78 uint32_t val; 79 } dscsr_reg_t; 80 #define ETH_PHY_DSCSR_REG_ADDR (0x11) 81 82 typedef struct { 83 esp_eth_phy_t parent; 84 esp_eth_mediator_t *eth; 85 uint32_t addr; 86 uint32_t reset_timeout_ms; 87 uint32_t autonego_timeout_ms; 88 eth_link_t link_status; 89 int reset_gpio_num; 90 } phy_dm9051_t; 91 92 static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051) 93 { 94 esp_eth_mediator_t *eth = dm9051->eth; 95 eth_speed_t speed = ETH_SPEED_10M; 96 eth_duplex_t duplex = ETH_DUPLEX_HALF; 97 uint32_t peer_pause_ability = false; 98 bmsr_reg_t bmsr; 99 dscsr_reg_t dscsr; 100 anlpar_reg_t anlpar; 101 // BMSR is a latch low register 102 // after power up, the first latched value must be 0, which means down 103 // to speed up power up link speed, double read this register as a workaround 104 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, 105 "read BMSR failed", err); 106 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, 107 "read BMSR failed", err); 108 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK, 109 "read ANLPAR failed", err); 110 eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; 111 /* check if link status changed */ 112 if (dm9051->link_status != link) { 113 /* when link up, read negotiation result */ 114 if (link == ETH_LINK_UP) { 115 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, 116 "read DSCSR failed", err); 117 if (dscsr.fdx100 || dscsr.hdx100) { 118 speed = ETH_SPEED_100M; 119 } else { 120 speed = ETH_SPEED_10M; 121 } 122 if (dscsr.fdx100 || dscsr.fdx10) { 123 duplex = ETH_DUPLEX_FULL; 124 } else { 125 duplex = ETH_DUPLEX_HALF; 126 } 127 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, 128 "change speed failed", err); 129 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, 130 "change duplex failed", err); 131 /* if we're in duplex mode, and peer has the flow control ability */ 132 if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) { 133 peer_pause_ability = 1; 134 } else { 135 peer_pause_ability = 0; 136 } 137 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK, 138 "change pause ability failed", err); 139 } 140 PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, 141 "change link failed", err); 142 dm9051->link_status = link; 143 } 144 return ESP_OK; 145 err: 146 return ESP_FAIL; 147 } 148 149 static esp_err_t dm9051_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth) 150 { 151 PHY_CHECK(eth, "can't set mediator to null", err); 152 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 153 dm9051->eth = eth; 154 return ESP_OK; 155 err: 156 return ESP_ERR_INVALID_ARG; 157 } 158 159 static esp_err_t dm9051_get_link(esp_eth_phy_t *phy) 160 { 161 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 162 /* Updata information about link, speed, duplex */ 163 PHY_CHECK(dm9051_update_link_duplex_speed(dm9051) == ESP_OK, "update link duplex speed failed", err); 164 return ESP_OK; 165 err: 166 return ESP_FAIL; 167 } 168 169 static esp_err_t dm9051_reset(esp_eth_phy_t *phy) 170 { 171 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 172 dm9051->link_status = ETH_LINK_DOWN; 173 esp_eth_mediator_t *eth = dm9051->eth; 174 dscr_reg_t dscr; 175 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, 176 "read DSCR failed", err); 177 dscr.smrst = 1; 178 PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK, 179 "write DSCR failed", err); 180 bmcr_reg_t bmcr = {.reset = 1}; 181 PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 182 "write BMCR failed", err); 183 /* Wait for reset complete */ 184 uint32_t to = 0; 185 for (to = 0; to < dm9051->reset_timeout_ms / 10; to++) { 186 vTaskDelay(pdMS_TO_TICKS(10)); 187 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 188 "read BMCR failed", err); 189 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK, 190 "read DSCR failed", err); 191 if (!bmcr.reset && !dscr.smrst) { 192 break; 193 } 194 } 195 PHY_CHECK(to < dm9051->reset_timeout_ms / 10, "PHY reset timeout", err); 196 return ESP_OK; 197 err: 198 return ESP_FAIL; 199 } 200 201 static esp_err_t dm9051_reset_hw(esp_eth_phy_t *phy) 202 { 203 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 204 // set reset_gpio_num minus zero can skip hardware reset phy chip 205 if (dm9051->reset_gpio_num >= 0) { 206 esp_rom_gpio_pad_select_gpio(dm9051->reset_gpio_num); 207 gpio_set_direction(dm9051->reset_gpio_num, GPIO_MODE_OUTPUT); 208 gpio_set_level(dm9051->reset_gpio_num, 0); 209 esp_rom_delay_us(100); // insert min input assert time 210 gpio_set_level(dm9051->reset_gpio_num, 1); 211 } 212 return ESP_OK; 213 } 214 215 static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy) 216 { 217 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 218 esp_eth_mediator_t *eth = dm9051->eth; 219 /* Start auto negotiation */ 220 bmcr_reg_t bmcr = { 221 .speed_select = 1, /* 100Mbps */ 222 .duplex_mode = 1, /* Full Duplex */ 223 .en_auto_nego = 1, /* Auto Negotiation */ 224 .restart_auto_nego = 1 /* Restart Auto Negotiation */ 225 }; 226 PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 227 "write BMCR failed", err); 228 /* Wait for auto negotiation complete */ 229 bmsr_reg_t bmsr; 230 dscsr_reg_t dscsr; 231 uint32_t to = 0; 232 for (to = 0; to < dm9051->autonego_timeout_ms / 10; to++) { 233 vTaskDelay(pdMS_TO_TICKS(10)); 234 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, 235 "read BMSR failed", err); 236 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK, 237 "read DSCSR failed", err); 238 if (bmsr.auto_nego_complete && dscsr.anmb & 0x08) { 239 break; 240 } 241 } 242 if (to >= dm9051->autonego_timeout_ms / 10) { 243 ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout"); 244 } 245 /* Updata information about link, speed, duplex */ 246 PHY_CHECK(dm9051_update_link_duplex_speed(dm9051) == ESP_OK, "update link duplex speed failed", err); 247 return ESP_OK; 248 err: 249 return ESP_FAIL; 250 } 251 252 static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable) 253 { 254 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 255 esp_eth_mediator_t *eth = dm9051->eth; 256 bmcr_reg_t bmcr; 257 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 258 "read BMCR failed", err); 259 if (!enable) { 260 /* Enable IEEE Power Down Mode */ 261 bmcr.power_down = 1; 262 } else { 263 /* Disable IEEE Power Down Mode */ 264 bmcr.power_down = 0; 265 } 266 PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, 267 "write BMCR failed", err); 268 if (!enable) { 269 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 270 "read BMCR failed", err); 271 PHY_CHECK(bmcr.power_down == 1, "power down failed", err); 272 } else { 273 /* wait for power up complete */ 274 uint32_t to = 0; 275 for (to = 0; to < dm9051->reset_timeout_ms / 10; to++) { 276 vTaskDelay(pdMS_TO_TICKS(10)); 277 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, 278 "read BMCR failed", err); 279 if (bmcr.power_down == 0) { 280 break; 281 } 282 } 283 PHY_CHECK(to < dm9051->reset_timeout_ms / 10, "power up timeout", err); 284 } 285 return ESP_OK; 286 err: 287 return ESP_FAIL; 288 } 289 290 static esp_err_t dm9051_set_addr(esp_eth_phy_t *phy, uint32_t addr) 291 { 292 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 293 dm9051->addr = addr; 294 return ESP_OK; 295 } 296 297 static esp_err_t dm9051_get_addr(esp_eth_phy_t *phy, uint32_t *addr) 298 { 299 PHY_CHECK(addr, "addr can't be null", err); 300 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 301 *addr = dm9051->addr; 302 return ESP_OK; 303 err: 304 return ESP_ERR_INVALID_ARG; 305 } 306 307 static esp_err_t dm9051_del(esp_eth_phy_t *phy) 308 { 309 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 310 free(dm9051); 311 return ESP_OK; 312 } 313 314 static esp_err_t dm9051_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability) 315 { 316 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 317 esp_eth_mediator_t *eth = dm9051->eth; 318 /* Set PAUSE function ability */ 319 anar_reg_t anar; 320 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK, 321 "read ANAR failed", err); 322 if (ability) { 323 anar.asymmetric_pause = 1; 324 anar.symmetric_pause = 1; 325 } else { 326 anar.asymmetric_pause = 0; 327 anar.symmetric_pause = 0; 328 } 329 PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK, 330 "write ANAR failed", err); 331 return ESP_OK; 332 err: 333 return ESP_FAIL; 334 } 335 336 static esp_err_t dm9051_init(esp_eth_phy_t *phy) 337 { 338 phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent); 339 esp_eth_mediator_t *eth = dm9051->eth; 340 // Detect PHY address 341 if (dm9051->addr == ESP_ETH_PHY_ADDR_AUTO) { 342 PHY_CHECK(esp_eth_detect_phy_addr(eth, &dm9051->addr) == ESP_OK, "Detect PHY address failed", err); 343 } 344 /* Power on Ethernet PHY */ 345 PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power control failed", err); 346 /* Reset Ethernet PHY */ 347 PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset failed", err); 348 /* Check PHY ID */ 349 phyidr1_reg_t id1; 350 phyidr2_reg_t id2; 351 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, 352 "read ID1 failed", err); 353 PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, 354 "read ID2 failed", err); 355 PHY_CHECK(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A, 356 "wrong chip ID", err); 357 return ESP_OK; 358 err: 359 return ESP_FAIL; 360 } 361 362 static esp_err_t dm9051_deinit(esp_eth_phy_t *phy) 363 { 364 /* Power off Ethernet PHY */ 365 PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power control failed", err); 366 return ESP_OK; 367 err: 368 return ESP_FAIL; 369 } 370 371 esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config) 372 { 373 PHY_CHECK(config, "can't set phy config to null", err); 374 phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t)); 375 PHY_CHECK(dm9051, "calloc dm9051 failed", err); 376 dm9051->addr = config->phy_addr; 377 dm9051->reset_timeout_ms = config->reset_timeout_ms; 378 dm9051->reset_gpio_num = config->reset_gpio_num; 379 dm9051->link_status = ETH_LINK_DOWN; 380 dm9051->autonego_timeout_ms = config->autonego_timeout_ms; 381 dm9051->parent.reset = dm9051_reset; 382 dm9051->parent.reset_hw = dm9051_reset_hw; 383 dm9051->parent.init = dm9051_init; 384 dm9051->parent.deinit = dm9051_deinit; 385 dm9051->parent.set_mediator = dm9051_set_mediator; 386 dm9051->parent.negotiate = dm9051_negotiate; 387 dm9051->parent.get_link = dm9051_get_link; 388 dm9051->parent.pwrctl = dm9051_pwrctl; 389 dm9051->parent.get_addr = dm9051_get_addr; 390 dm9051->parent.set_addr = dm9051_set_addr; 391 dm9051->parent.advertise_pause_ability = dm9051_advertise_pause_ability; 392 dm9051->parent.del = dm9051_del; 393 return &(dm9051->parent); 394 err: 395 return NULL; 396 }