/ components / esp_eth / src / esp_eth_phy_ip101.c
esp_eth_phy_ip101.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 = "ip101";
 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 PCR(Page Control Register)
 41   *
 42   */
 43  typedef union {
 44      struct {
 45          uint32_t register_page_select : 5; /* Select register page, default is 16 */
 46          uint32_t reserved : 11;            /* Reserved */
 47      };
 48      uint32_t val;
 49  } pcr_reg_t;
 50  #define ETH_PHY_PCR_REG_ADDR (0x14)
 51  
 52  /**
 53   * @brief ISR(Interrupt Status Register), Page 16
 54   *
 55   */
 56  typedef union {
 57      struct {
 58          uint32_t link_changed : 1;   /* Flag to indicate link status change interrupt */
 59          uint32_t duplex_changed : 1; /* Flag to indicate duplex change interrupt */
 60          uint32_t speed_changed : 1;  /* Flag to indicate speed change interrupt */
 61          uint32_t intr_status : 1;    /* Flag to indicate interrupt status */
 62          uint32_t reserved1 : 4;      /* Reserved */
 63          uint32_t link_mask : 1;      /* Mask link change interrupt */
 64          uint32_t duplex_mask : 1;    /* Mask duplex change interrupt */
 65          uint32_t speed_mask : 1;     /* Mask speed change interrupt */
 66          uint32_t all_mask : 1;       /* Mask all interrupt */
 67          uint32_t reserved2 : 3;      /* Reserved */
 68          uint32_t use_intr_pin : 1;   /* Set high to use INTR and INTR_32 as an interrupt pin */
 69      };
 70      uint32_t val;
 71  } isr_reg_t;
 72  #define ETH_PHY_ISR_REG_ADDR (0x11)
 73  
 74  /**
 75   * @brief PHY MDI/MDIX Control and Specific Status Register, Page 16
 76   *
 77   */
 78  typedef union {
 79      struct {
 80          uint32_t op_mode : 3;    /* Operation Mode Idicator */
 81          uint32_t force_mdix : 1; /* Force the MDIX channel to be selected */
 82          uint32_t reserved1 : 4;  /* Reserved */
 83          uint32_t link_up : 1;    /* Indicate the link status is OK or FAIL */
 84          uint32_t reserved2 : 7;  /* Reserved */
 85      };
 86      uint32_t val;
 87  } cssr_reg_t;
 88  #define ETH_PHY_CSSR_REG_ADDR (0x1E)
 89  
 90  /**
 91   * @brief PSCR(PHY Specific Control Register), Page 1
 92   *
 93   */
 94  typedef union {
 95      struct {
 96          uint32_t reserved1 : 7;      /* Reserved */
 97          uint32_t force_link_100 : 1; /* Force Link 100 */
 98          uint32_t force_link_10 : 1;  /* Force Link 10 */
 99          uint32_t reserved2 : 7;      /* Reserved */
100      };
101      uint32_t val;
102  } pscr_reg_t;
103  #define ETH_PHY_PSCR_REG_ADDR (0x11)
104  
105  typedef struct {
106      esp_eth_phy_t parent;
107      esp_eth_mediator_t *eth;
108      uint32_t addr;
109      uint32_t reset_timeout_ms;
110      uint32_t autonego_timeout_ms;
111      eth_link_t link_status;
112      int reset_gpio_num;
113  } phy_ip101_t;
114  
115  static esp_err_t ip101_page_select(phy_ip101_t *ip101, uint32_t page)
116  {
117      esp_eth_mediator_t *eth = ip101->eth;
118      pcr_reg_t pcr = {
119          .register_page_select = page
120      };
121      PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_PCR_REG_ADDR, pcr.val) == ESP_OK, "write PCR failed", err);
122      return ESP_OK;
123  err:
124      return ESP_FAIL;
125  }
126  
127  static esp_err_t ip101_update_link_duplex_speed(phy_ip101_t *ip101)
128  {
129      esp_eth_mediator_t *eth = ip101->eth;
130      eth_speed_t speed = ETH_SPEED_10M;
131      eth_duplex_t duplex = ETH_DUPLEX_HALF;
132      uint32_t peer_pause_ability = false;
133      cssr_reg_t cssr;
134      anlpar_reg_t anlpar;
135      PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page 16 failed", err);
136      PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK,
137                "read CSSR failed", err);
138      PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK,
139                "read ANLPAR failed", err);
140      eth_link_t link = cssr.link_up ? ETH_LINK_UP : ETH_LINK_DOWN;
141      /* check if link status changed */
142      if (ip101->link_status != link) {
143          /* when link up, read negotiation result */
144          if (link == ETH_LINK_UP) {
145              switch (cssr.op_mode) {
146              case 1: //10M Half
147                  speed = ETH_SPEED_10M;
148                  duplex = ETH_DUPLEX_HALF;
149                  break;
150              case 2: //100M Half
151                  speed = ETH_SPEED_100M;
152                  duplex = ETH_DUPLEX_HALF;
153                  break;
154              case 5: //10M Full
155                  speed = ETH_SPEED_10M;
156                  duplex = ETH_DUPLEX_FULL;
157                  break;
158              case 6: //100M Full
159                  speed = ETH_SPEED_100M;
160                  duplex = ETH_DUPLEX_FULL;
161                  break;
162              default:
163                  break;
164              }
165              PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
166                        "change speed failed", err);
167              PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
168                        "change duplex failed", err);
169              /* if we're in duplex mode, and peer has the flow control ability */
170              if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
171                  peer_pause_ability = 1;
172              } else {
173                  peer_pause_ability = 0;
174              }
175              PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK,
176                        "change pause ability failed", err);
177          }
178          PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
179                    "chagne link failed", err);
180          ip101->link_status = link;
181      }
182      return ESP_OK;
183  err:
184      return ESP_FAIL;
185  }
186  
187  static esp_err_t ip101_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
188  {
189      PHY_CHECK(eth, "can't set mediator to null", err);
190      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
191      ip101->eth = eth;
192      return ESP_OK;
193  err:
194      return ESP_ERR_INVALID_ARG;
195  }
196  
197  static esp_err_t ip101_get_link(esp_eth_phy_t *phy)
198  {
199      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
200      /* Updata information about link, speed, duplex */
201      PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err);
202      return ESP_OK;
203  err:
204      return ESP_FAIL;
205  }
206  
207  static esp_err_t ip101_reset(esp_eth_phy_t *phy)
208  {
209      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
210      ip101->link_status = ETH_LINK_DOWN;
211      esp_eth_mediator_t *eth = ip101->eth;
212      bmcr_reg_t bmcr = {.reset = 1};
213      PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
214                "write BMCR failed", err);
215      /* wait for reset complete */
216      uint32_t to = 0;
217      for (to = 0; to < ip101->reset_timeout_ms / 10; to++) {
218          vTaskDelay(pdMS_TO_TICKS(10));
219          PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
220                    "read BMCR failed", err);
221          if (!bmcr.reset) {
222              break;
223          }
224      }
225      PHY_CHECK(to < ip101->reset_timeout_ms / 10, "reset timeout", err);
226      return ESP_OK;
227  err:
228      return ESP_FAIL;
229  }
230  
231  static esp_err_t ip101_reset_hw(esp_eth_phy_t *phy)
232  {
233      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
234      if (ip101->reset_gpio_num >= 0) {
235          esp_rom_gpio_pad_select_gpio(ip101->reset_gpio_num);
236          gpio_set_direction(ip101->reset_gpio_num, GPIO_MODE_OUTPUT);
237          gpio_set_level(ip101->reset_gpio_num, 0);
238          esp_rom_delay_us(100); // insert min input assert time
239          gpio_set_level(ip101->reset_gpio_num, 1);
240      }
241      return ESP_OK;
242  }
243  
244  static esp_err_t ip101_negotiate(esp_eth_phy_t *phy)
245  {
246      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
247      esp_eth_mediator_t *eth = ip101->eth;
248      /* Restart auto negotiation */
249      bmcr_reg_t bmcr = {
250          .speed_select = 1,     /* 100Mbps */
251          .duplex_mode = 1,      /* Full Duplex */
252          .en_auto_nego = 1,     /* Auto Negotiation */
253          .restart_auto_nego = 1 /* Restart Auto Negotiation */
254      };
255      PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
256                "write BMCR failed", err);
257      /* Wait for auto negotiation complete */
258      bmsr_reg_t bmsr;
259      uint32_t to = 0;
260      for (to = 0; to < ip101->autonego_timeout_ms / 10; to++) {
261          vTaskDelay(pdMS_TO_TICKS(10));
262          PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
263                    "read BMSR failed", err);
264          if (bmsr.auto_nego_complete) {
265              break;
266          }
267      }
268      /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
269      if (to >= ip101->autonego_timeout_ms / 10) {
270          ESP_LOGW(TAG, "auto negotiation timeout");
271      }
272      /* Updata information about link, speed, duplex */
273      PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err);
274      return ESP_OK;
275  err:
276      return ESP_FAIL;
277  }
278  
279  static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable)
280  {
281      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
282      esp_eth_mediator_t *eth = ip101->eth;
283      bmcr_reg_t bmcr;
284      PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
285                "read BMCR failed", err);
286      if (!enable) {
287          /* Enable IEEE Power Down Mode */
288          bmcr.power_down = 1;
289      } else {
290          /* Disable IEEE Power Down Mode */
291          bmcr.power_down = 0;
292      }
293      PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
294                "write BMCR failed", err);
295      if (!enable) {
296          PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
297                    "read BMCR failed", err);
298          PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
299      } else {
300          /* wait for power up complete */
301          uint32_t to = 0;
302          for (to = 0; to < ip101->reset_timeout_ms / 10; to++) {
303              vTaskDelay(pdMS_TO_TICKS(10));
304              PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
305                        "read BMCR failed", err);
306              if (bmcr.power_down == 0) {
307                  break;
308              }
309          }
310          PHY_CHECK(to < ip101->reset_timeout_ms / 10, "power up timeout", err);
311      }
312      return ESP_OK;
313  err:
314      return ESP_FAIL;
315  }
316  
317  static esp_err_t ip101_set_addr(esp_eth_phy_t *phy, uint32_t addr)
318  {
319      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
320      ip101->addr = addr;
321      return ESP_OK;
322  }
323  
324  static esp_err_t ip101_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
325  {
326      PHY_CHECK(addr, "addr can't be null", err);
327      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
328      *addr = ip101->addr;
329      return ESP_OK;
330  err:
331      return ESP_ERR_INVALID_ARG;
332  }
333  
334  static esp_err_t ip101_del(esp_eth_phy_t *phy)
335  {
336      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
337      free(ip101);
338      return ESP_OK;
339  }
340  
341  static esp_err_t ip101_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
342  {
343      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
344      esp_eth_mediator_t *eth = ip101->eth;
345      /* Set PAUSE function ability */
346      anar_reg_t anar;
347      PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK,
348                "read ANAR failed", err);
349      if (ability) {
350          anar.asymmetric_pause = 1;
351          anar.symmetric_pause = 1;
352      } else {
353          anar.asymmetric_pause = 0;
354          anar.symmetric_pause = 0;
355      }
356      PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK,
357                "write ANAR failed", err);
358      return ESP_OK;
359  err:
360      return ESP_FAIL;
361  }
362  
363  static esp_err_t ip101_init(esp_eth_phy_t *phy)
364  {
365      phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
366      esp_eth_mediator_t *eth = ip101->eth;
367      // Detect PHY address
368      if (ip101->addr == ESP_ETH_PHY_ADDR_AUTO) {
369          PHY_CHECK(esp_eth_detect_phy_addr(eth, &ip101->addr) == ESP_OK, "Detect PHY address failed", err);
370      }
371      /* Power on Ethernet PHY */
372      PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power control failed", err);
373      /* Reset Ethernet PHY */
374      PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset failed", err);
375      /* Check PHY ID */
376      phyidr1_reg_t id1;
377      phyidr2_reg_t id2;
378      PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
379      PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
380      PHY_CHECK(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, "wrong chip ID", err);
381      return ESP_OK;
382  err:
383      return ESP_FAIL;
384  }
385  
386  static esp_err_t ip101_deinit(esp_eth_phy_t *phy)
387  {
388      /* Power off Ethernet PHY */
389      PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power control failed", err);
390      return ESP_OK;
391  err:
392      return ESP_FAIL;
393  }
394  
395  esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config)
396  {
397      PHY_CHECK(config, "can't set phy config to null", err);
398      phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t));
399      PHY_CHECK(ip101, "calloc ip101 failed", err);
400      ip101->addr = config->phy_addr;
401      ip101->reset_timeout_ms = config->reset_timeout_ms;
402      ip101->reset_gpio_num = config->reset_gpio_num;
403      ip101->link_status = ETH_LINK_DOWN;
404      ip101->autonego_timeout_ms = config->autonego_timeout_ms;
405      ip101->parent.reset = ip101_reset;
406      ip101->parent.reset_hw = ip101_reset_hw;
407      ip101->parent.init = ip101_init;
408      ip101->parent.deinit = ip101_deinit;
409      ip101->parent.set_mediator = ip101_set_mediator;
410      ip101->parent.negotiate = ip101_negotiate;
411      ip101->parent.get_link = ip101_get_link;
412      ip101->parent.pwrctl = ip101_pwrctl;
413      ip101->parent.get_addr = ip101_get_addr;
414      ip101->parent.set_addr = ip101_set_addr;
415      ip101->parent.advertise_pause_ability = ip101_advertise_pause_ability;
416      ip101->parent.del = ip101_del;
417  
418      return &(ip101->parent);
419  err:
420      return NULL;
421  }