/ components / esp_eth / src / esp_eth_phy_ksz8041.c
esp_eth_phy_ksz8041.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 = "ksz8041";
 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   * @brief PC2R(PHY Control 2 Register)
 40   *
 41   */
 42  typedef union {
 43      struct {
 44          uint32_t hp_mdix : 1;          /* HP Auto MDI/MDI-X Mode */
 45          uint32_t mdi_x_select : 1;     /* MDI/MDI-X Select */
 46          uint32_t pairswap_dis : 1;     /* Disable Auto MDI/MDI-X */
 47          uint32_t energy_det : 1;       /* Presence of Signal on RX+/- Wire Pair */
 48          uint32_t force_link : 1;       /* Force Link Pass */
 49          uint32_t power_saving : 1;     /* Enable Powering Saving */
 50          uint32_t irq_level : 1;        /* Interrupt Pin Active Level */
 51          uint32_t jabber : 1;           /* Enable Jabber Counter */
 52          uint32_t auto_nego_comp : 1;   /* Auto Negotiation Complete */
 53          uint32_t flow_ctl_cap : 1;     /* Flow Control Capable */
 54          uint32_t phy_iso : 1;          /* PHY in Isolate Mode */
 55          uint32_t op_mode_ind : 3;      /* Operation Mode Indication */
 56          uint32_t en_sqe_test : 1;      /* Enable SQE Test */
 57          uint32_t dis_data_scr: 1;      /* Disable Scrambler */
 58      };
 59      uint32_t val;
 60  } pc2r_reg_t;
 61  #define ETH_PHY_PC2R_REG_ADDR (0x1F)
 62  
 63  typedef struct {
 64      esp_eth_phy_t parent;
 65      esp_eth_mediator_t *eth;
 66      uint32_t addr;
 67      uint32_t reset_timeout_ms;
 68      uint32_t autonego_timeout_ms;
 69      eth_link_t link_status;
 70      int reset_gpio_num;
 71  } phy_ksz8041_t;
 72  
 73  static esp_err_t ksz8041_update_link_duplex_speed(phy_ksz8041_t *ksz8041)
 74  {
 75      esp_eth_mediator_t *eth = ksz8041->eth;
 76      eth_speed_t speed = ETH_SPEED_10M;
 77      eth_duplex_t duplex = ETH_DUPLEX_HALF;
 78      uint32_t peer_pause_ability = false;
 79      anlpar_reg_t anlpar;
 80      bmsr_reg_t bmsr;
 81      pc2r_reg_t pc2r;
 82      PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK,
 83                "read ANLPAR failed", err);
 84      PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
 85                "read BMSR failed", err);
 86      eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
 87      /* check if link status changed */
 88      if (ksz8041->link_status != link) {
 89          /* when link up, read negotiation result */
 90          if (link == ETH_LINK_UP) {
 91              PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_PC2R_REG_ADDR, &(pc2r.val)) == ESP_OK,
 92                        "read PC2R failed", err);
 93              switch (pc2r.op_mode_ind) {
 94              case 1: //10Base-T half-duplex
 95                  speed = ETH_SPEED_10M;
 96                  duplex = ETH_DUPLEX_HALF;
 97                  break;
 98              case 2: //100Base-TX half-duplex
 99                  speed = ETH_SPEED_100M;
100                  duplex = ETH_DUPLEX_HALF;
101                  break;
102              case 5: //10Base-T full-duplex
103                  speed = ETH_SPEED_10M;
104                  duplex = ETH_DUPLEX_FULL;
105                  break;
106              case 6: //100Base-TX full-duplex
107                  speed = ETH_SPEED_100M;
108                  duplex = ETH_DUPLEX_FULL;
109                  break;
110              default:
111                  break;
112              }
113              PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
114                        "change speed failed", err);
115              PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
116                        "change duplex failed", err);
117              /* if we're in duplex mode, and peer has the flow control ability */
118              if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
119                  peer_pause_ability = 1;
120              } else {
121                  peer_pause_ability = 0;
122              }
123              PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK,
124                        "change pause ability failed", err);
125          }
126          PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
127                    "change link failed", err);
128          ksz8041->link_status = link;
129      }
130      return ESP_OK;
131  err:
132      return ESP_FAIL;
133  }
134  
135  static esp_err_t ksz8041_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
136  {
137      PHY_CHECK(eth, "can't set mediator to null", err);
138      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
139      ksz8041->eth = eth;
140      return ESP_OK;
141  err:
142      return ESP_ERR_INVALID_ARG;
143  }
144  
145  static esp_err_t ksz8041_get_link(esp_eth_phy_t *phy)
146  {
147      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
148      /* Update information about link, speed, duplex */
149      PHY_CHECK(ksz8041_update_link_duplex_speed(ksz8041) == ESP_OK, "update link duplex speed failed", err);
150      return ESP_OK;
151  err:
152      return ESP_FAIL;
153  }
154  
155  static esp_err_t ksz8041_reset(esp_eth_phy_t *phy)
156  {
157      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
158      ksz8041->link_status = ETH_LINK_DOWN;
159      esp_eth_mediator_t *eth = ksz8041->eth;
160      bmcr_reg_t bmcr = {.reset = 1};
161      PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
162                "write BMCR failed", err);
163      /* wait for reset complete */
164      uint32_t to = 0;
165      for (to = 0; to < ksz8041->reset_timeout_ms / 10; to++) {
166          vTaskDelay(pdMS_TO_TICKS(10));
167          PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
168                    "read BMCR failed", err);
169          if (!bmcr.reset) {
170              break;
171          }
172      }
173      PHY_CHECK(to < ksz8041->reset_timeout_ms / 10, "reset timeout", err);
174      return ESP_OK;
175  err:
176      return ESP_FAIL;
177  }
178  
179  static esp_err_t ksz8041_reset_hw(esp_eth_phy_t *phy)
180  {
181      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
182      if (ksz8041->reset_gpio_num >= 0) {
183          esp_rom_gpio_pad_select_gpio(ksz8041->reset_gpio_num);
184          gpio_set_direction(ksz8041->reset_gpio_num, GPIO_MODE_OUTPUT);
185          gpio_set_level(ksz8041->reset_gpio_num, 0);
186          esp_rom_delay_us(100); // insert min input assert time
187          gpio_set_level(ksz8041->reset_gpio_num, 1);
188      }
189      return ESP_OK;
190  }
191  
192  static esp_err_t ksz8041_negotiate(esp_eth_phy_t *phy)
193  {
194      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
195      esp_eth_mediator_t *eth = ksz8041->eth;
196      /* Restart auto negotiation */
197      bmcr_reg_t bmcr = {
198          .speed_select = 1,     /* 100Mbps */
199          .duplex_mode = 1,      /* Full Duplex */
200          .en_auto_nego = 1,     /* Auto Negotiation */
201          .restart_auto_nego = 1 /* Restart Auto Negotiation */
202      };
203      PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
204      /* Wait for auto negotiation complete */
205      bmsr_reg_t bmsr;
206      pc2r_reg_t pc2r;
207      int32_t to = 0;
208      for (to = 0; to < ksz8041->autonego_timeout_ms / 10; to++) {
209          vTaskDelay(pdMS_TO_TICKS(10));
210          PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
211                    "read BMSR failed", err);
212          PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_PC2R_REG_ADDR, &(pc2r.val)) == ESP_OK,
213                    "read PC2R failed", err);
214          if (bmsr.auto_nego_complete && pc2r.auto_nego_comp) {
215              break;
216          }
217      }
218      /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
219      if (to >= ksz8041->autonego_timeout_ms / 10) {
220          ESP_LOGW(TAG, "auto negotiation timeout");
221      }
222      /* Updata information about link, speed, duplex */
223      PHY_CHECK(ksz8041_update_link_duplex_speed(ksz8041) == ESP_OK, "update link duplex speed failed", err);
224      return ESP_OK;
225  err:
226      return ESP_FAIL;
227  }
228  
229  static esp_err_t ksz8041_pwrctl(esp_eth_phy_t *phy, bool enable)
230  {
231      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
232      esp_eth_mediator_t *eth = ksz8041->eth;
233      bmcr_reg_t bmcr;
234      PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
235                "read BMCR failed", err);
236      if (!enable) {
237          /* General Power Down Mode */
238          bmcr.power_down = 1;
239      } else {
240          /* Normal operation Mode */
241          bmcr.power_down = 0;
242      }
243      PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
244                "write BMCR failed", err);
245      if (!enable) {
246          PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
247                    "read BMCR failed", err);
248          PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
249      } else {
250          /* wait for power up complete */
251          uint32_t to = 0;
252          for (to = 0; to < ksz8041->reset_timeout_ms / 10; to++) {
253              vTaskDelay(pdMS_TO_TICKS(10));
254              PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
255                        "read BMCR failed", err);
256              if (bmcr.power_down == 0) {
257                  break;
258              }
259          }
260          PHY_CHECK(to < ksz8041->reset_timeout_ms / 10, "power up timeout", err);
261      }
262      return ESP_OK;
263  err:
264      return ESP_FAIL;
265  }
266  
267  static esp_err_t ksz8041_set_addr(esp_eth_phy_t *phy, uint32_t addr)
268  {
269      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
270      ksz8041->addr = addr;
271      return ESP_OK;
272  }
273  
274  static esp_err_t ksz8041_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
275  {
276      PHY_CHECK(addr, "addr can't be null", err);
277      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
278      *addr = ksz8041->addr;
279      return ESP_OK;
280  err:
281      return ESP_ERR_INVALID_ARG;
282  }
283  
284  static esp_err_t ksz8041_del(esp_eth_phy_t *phy)
285  {
286      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
287      free(ksz8041);
288      return ESP_OK;
289  }
290  
291  static esp_err_t ksz8041_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
292  {
293      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
294      esp_eth_mediator_t *eth = ksz8041->eth;
295      /* Set PAUSE function ability */
296      anar_reg_t anar;
297      PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK,
298                "read ANAR failed", err);
299      if (ability) {
300          anar.asymmetric_pause = 1;
301          anar.symmetric_pause = 1;
302      } else {
303          anar.asymmetric_pause = 0;
304          anar.symmetric_pause = 0;
305      }
306      PHY_CHECK(eth->phy_reg_write(eth, ksz8041->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK,
307                "write ANAR failed", err);
308      return ESP_OK;
309  err:
310      return ESP_FAIL;
311  }
312  
313  static esp_err_t ksz8041_init(esp_eth_phy_t *phy)
314  {
315      phy_ksz8041_t *ksz8041 = __containerof(phy, phy_ksz8041_t, parent);
316      esp_eth_mediator_t *eth = ksz8041->eth;
317      /* Power on Ethernet PHY */
318      PHY_CHECK(ksz8041_pwrctl(phy, true) == ESP_OK, "power control failed", err);
319      /* Reset Ethernet PHY */
320      PHY_CHECK(ksz8041_reset(phy) == ESP_OK, "reset failed", err);
321      /* Check PHY ID */
322      phyidr1_reg_t id1;
323      phyidr2_reg_t id2;
324      PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
325                "read ID1 failed", err);
326      PHY_CHECK(eth->phy_reg_read(eth, ksz8041->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
327                "read ID2 failed", err);
328      PHY_CHECK(id1.oui_msb == 0x22 && id2.oui_lsb == 0x5 && id2.vendor_model == 0x11, "wrong chip ID", err);
329      return ESP_OK;
330  err:
331      return ESP_FAIL;
332  }
333  
334  static esp_err_t ksz8041_deinit(esp_eth_phy_t *phy)
335  {
336      /* Power off Ethernet PHY */
337      PHY_CHECK(ksz8041_pwrctl(phy, false) == ESP_OK, "power control failed", err);
338      return ESP_OK;
339  err:
340      return ESP_FAIL;
341  }
342  
343  esp_eth_phy_t *esp_eth_phy_new_ksz8041(const eth_phy_config_t *config)
344  {
345      PHY_CHECK(config, "can't set phy config to null", err);
346      phy_ksz8041_t *ksz8041 = calloc(1, sizeof(phy_ksz8041_t));
347      PHY_CHECK(ksz8041, "calloc ksz8041 failed", err);
348      ksz8041->addr = config->phy_addr;
349      ksz8041->reset_gpio_num = config->reset_gpio_num;
350      ksz8041->reset_timeout_ms = config->reset_timeout_ms;
351      ksz8041->link_status = ETH_LINK_DOWN;
352      ksz8041->autonego_timeout_ms = config->autonego_timeout_ms;
353      ksz8041->parent.reset = ksz8041_reset;
354      ksz8041->parent.reset_hw = ksz8041_reset_hw;
355      ksz8041->parent.init = ksz8041_init;
356      ksz8041->parent.deinit = ksz8041_deinit;
357      ksz8041->parent.set_mediator = ksz8041_set_mediator;
358      ksz8041->parent.negotiate = ksz8041_negotiate;
359      ksz8041->parent.get_link = ksz8041_get_link;
360      ksz8041->parent.pwrctl = ksz8041_pwrctl;
361      ksz8041->parent.get_addr = ksz8041_get_addr;
362      ksz8041->parent.set_addr = ksz8041_set_addr;
363      ksz8041->parent.advertise_pause_ability = ksz8041_advertise_pause_ability;
364      ksz8041->parent.del = ksz8041_del;
365  
366      return &(ksz8041->parent);
367  err:
368      return NULL;
369  }