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 = "dp83848";
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 PHYSTS(PHY Status Register)
41  *
42  */
43 typedef union {
44     struct {
45         uint32_t link_status : 1;               /* Link Status */
46         uint32_t speed_status : 1;              /* Speed Status */
47         uint32_t duplex_status : 1;             /* Duplex Status */
48         uint32_t loopback_status : 1;           /* MII Loopback */
49         uint32_t auto_nego_complete : 1;        /* Auto-Negotiation Complete */
50         uint32_t jabber_detect : 1;             /* Jabber Detect */
51         uint32_t remote_fault : 1;              /* Remote Fault */
52         uint32_t mii_interrupt : 1;             /* MII Interrupt Pending */
53         uint32_t page_received : 1;             /* Link Code Word Page Received */
54         uint32_t descrambler_lock : 1;          /* Descrambler Lock */
55         uint32_t signal_detect : 1;             /* Signal Detect */
56         uint32_t false_carrier_sense_latch : 1; /* False Carrier Sense Latch */
57         uint32_t polarity_status : 1;           /* Polarity Status */
58         uint32_t receive_error_latch : 1;       /* Receive Error Latch */
59         uint32_t mdix_mode : 1;                 /* MDI-X mode reported by auto-negotiation */
60         uint32_t reserved : 1;                  /* Reserved */
61     };
62     uint32_t val;
63 } physts_reg_t;
64 #define ETH_PHY_STS_REG_ADDR (0x10)
65 
66 /**
67  * @brief PHYCR(PHY Control Register)
68  *
69  */
70 typedef union {
71     struct {
72         uint32_t phy_addr : 5;               /* PHY Address */
73         uint32_t led_cfg : 2;                /* LED Configuration Modes */
74         uint32_t bypass_led_stretching : 1;  /* Bypass LED Stretching */
75         uint32_t bist_start : 1;             /* BIST Start */
76         uint32_t bist_status : 1;            /* BIST Test Status */
77         uint32_t psr_15 : 1;                 /* BIST Sequence select */
78         uint32_t bist_force_error : 1;       /* BIST Force Error */
79         uint32_t pause_trans_negotiate : 1;  /* Pause Transmit Negotiated Status */
80         uint32_t pause_receive_negotiat : 1; /* Pause Receive Negotiated Status */
81         uint32_t force_mdix : 1;             /* Force MDIX */
82         uint32_t en_auto_mdix : 1;           /* Auto-MDIX Enable */
83     };
84     uint32_t val;
85 } phycr_reg_t;
86 #define ETH_PHY_CR_REG_ADDR (0x19)
87 
88 typedef struct {
89     esp_eth_phy_t parent;
90     esp_eth_mediator_t *eth;
91     int addr;
92     uint32_t reset_timeout_ms;
93     uint32_t autonego_timeout_ms;
94     eth_link_t link_status;
95     int reset_gpio_num;
96 } phy_dp83848_t;
97 
dp83848_update_link_duplex_speed(phy_dp83848_t * dp83848)98 static esp_err_t dp83848_update_link_duplex_speed(phy_dp83848_t *dp83848)
99 {
100     esp_eth_mediator_t *eth = dp83848->eth;
101     eth_speed_t speed = ETH_SPEED_10M;
102     eth_duplex_t duplex = ETH_DUPLEX_HALF;
103     uint32_t peer_pause_ability = false;
104     anlpar_reg_t anlpar;
105     physts_reg_t physts;
106     PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK,
107               "read ANLPAR failed", err);
108     PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK,
109               "read PHYSTS failed", err);
110     eth_link_t link = physts.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
111     /* check if link status changed */
112     if (dp83848->link_status != link) {
113         /* when link up, read negotiation result */
114         if (link == ETH_LINK_UP) {
115             if (physts.speed_status) {
116                 speed = ETH_SPEED_10M;
117             } else {
118                 speed = ETH_SPEED_100M;
119             }
120             if (physts.duplex_status) {
121                 duplex = ETH_DUPLEX_FULL;
122             } else {
123                 duplex = ETH_DUPLEX_HALF;
124             }
125             PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
126                       "change speed failed", err);
127             PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
128                       "change duplex failed", err);
129             /* if we're in duplex mode, and peer has the flow control ability */
130             if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
131                 peer_pause_ability = 1;
132             } else {
133                 peer_pause_ability = 0;
134             }
135             PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK,
136                       "change pause ability failed", err);
137         }
138         PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
139                   "change link failed", err);
140         dp83848->link_status = link;
141     }
142     return ESP_OK;
143 err:
144     return ESP_FAIL;
145 }
146 
dp83848_set_mediator(esp_eth_phy_t * phy,esp_eth_mediator_t * eth)147 static esp_err_t dp83848_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
148 {
149     PHY_CHECK(eth, "can't set mediator to null", err);
150     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
151     dp83848->eth = eth;
152     return ESP_OK;
153 err:
154     return ESP_ERR_INVALID_ARG;
155 }
156 
dp83848_get_link(esp_eth_phy_t * phy)157 static esp_err_t dp83848_get_link(esp_eth_phy_t *phy)
158 {
159     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
160     /* Updata information about link, speed, duplex */
161     PHY_CHECK(dp83848_update_link_duplex_speed(dp83848) == ESP_OK, "update link duplex speed failed", err);
162     return ESP_OK;
163 err:
164     return ESP_FAIL;
165 }
166 
dp83848_reset(esp_eth_phy_t * phy)167 static esp_err_t dp83848_reset(esp_eth_phy_t *phy)
168 {
169     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
170     dp83848->link_status = ETH_LINK_DOWN;
171     esp_eth_mediator_t *eth = dp83848->eth;
172     bmcr_reg_t bmcr = {.reset = 1};
173     PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
174               "write BMCR failed", err);
175     /* Wait for reset complete */
176     uint32_t to = 0;
177     for (to = 0; to < dp83848->reset_timeout_ms / 10; to++) {
178         vTaskDelay(pdMS_TO_TICKS(10));
179         PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
180                   "read BMCR failed", err);
181         if (!bmcr.reset) {
182             break;
183         }
184     }
185     PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "reset timeout", err);
186     return ESP_OK;
187 err:
188     return ESP_FAIL;
189 }
190 
dp83848_reset_hw(esp_eth_phy_t * phy)191 static esp_err_t dp83848_reset_hw(esp_eth_phy_t *phy)
192 {
193     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
194     if (dp83848->reset_gpio_num >= 0) {
195         esp_rom_gpio_pad_select_gpio(dp83848->reset_gpio_num);
196         gpio_set_direction(dp83848->reset_gpio_num, GPIO_MODE_OUTPUT);
197         gpio_set_level(dp83848->reset_gpio_num, 0);
198         esp_rom_delay_us(100); // insert min input assert time
199         gpio_set_level(dp83848->reset_gpio_num, 1);
200     }
201     return ESP_OK;
202 }
203 
dp83848_negotiate(esp_eth_phy_t * phy)204 static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy)
205 {
206     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
207     esp_eth_mediator_t *eth = dp83848->eth;
208     /* Start auto negotiation */
209     bmcr_reg_t bmcr = {
210         .speed_select = 1,     /* 100Mbps */
211         .duplex_mode = 1,      /* Full Duplex */
212         .en_auto_nego = 1,     /* Auto Negotiation */
213         .restart_auto_nego = 1 /* Restart Auto Negotiation */
214     };
215     PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
216               "write BMCR failed", err);
217     /* Wait for auto negotiation complete */
218     bmsr_reg_t bmsr;
219     physts_reg_t physts;
220     uint32_t to = 0;
221     for (to = 0; to < dp83848->autonego_timeout_ms / 10; to++) {
222         vTaskDelay(pdMS_TO_TICKS(10));
223         PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
224                   "read BMSR failed", err);
225         PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK,
226                   "read PHYSTS failed", err);
227         if (bmsr.auto_nego_complete && physts.auto_nego_complete) {
228             break;
229         }
230     }
231     /* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
232     if (to >= dp83848->autonego_timeout_ms / 10) {
233         ESP_LOGW(TAG, "auto negotiation timeout");
234     }
235     /* Updata information about link, speed, duplex */
236     PHY_CHECK(dp83848_update_link_duplex_speed(dp83848) == ESP_OK, "update link duplex speed failed", err);
237     return ESP_OK;
238 err:
239     return ESP_FAIL;
240 }
241 
dp83848_pwrctl(esp_eth_phy_t * phy,bool enable)242 static esp_err_t dp83848_pwrctl(esp_eth_phy_t *phy, bool enable)
243 {
244     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
245     esp_eth_mediator_t *eth = dp83848->eth;
246     bmcr_reg_t bmcr;
247     PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
248               "read BMCR failed", err);
249     if (!enable) {
250         /* Enable IEEE Power Down Mode */
251         bmcr.power_down = 1;
252     } else {
253         /* Disable IEEE Power Down Mode */
254         bmcr.power_down = 0;
255     }
256     PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
257               "write BMCR failed", err);
258     if (!enable) {
259         PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
260                   "read BMCR failed", err);
261         PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
262     } else {
263         /* wait for power up complete */
264         uint32_t to = 0;
265         for (to = 0; to < dp83848->reset_timeout_ms / 10; to++) {
266             vTaskDelay(pdMS_TO_TICKS(10));
267             PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
268                       "read BMCR failed", err);
269             if (bmcr.power_down == 0) {
270                 break;
271             }
272         }
273         PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "power up timeout", err);
274     }
275     return ESP_OK;
276 err:
277     return ESP_FAIL;
278 }
279 
dp83848_set_addr(esp_eth_phy_t * phy,uint32_t addr)280 static esp_err_t dp83848_set_addr(esp_eth_phy_t *phy, uint32_t addr)
281 {
282     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
283     dp83848->addr = addr;
284     return ESP_OK;
285 }
286 
dp83848_get_addr(esp_eth_phy_t * phy,uint32_t * addr)287 static esp_err_t dp83848_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
288 {
289     PHY_CHECK(addr, "addr can't be null", err);
290     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
291     *addr = dp83848->addr;
292     return ESP_OK;
293 err:
294     return ESP_ERR_INVALID_ARG;
295 }
296 
dp83848_del(esp_eth_phy_t * phy)297 static esp_err_t dp83848_del(esp_eth_phy_t *phy)
298 {
299     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
300     free(dp83848);
301     return ESP_OK;
302 }
303 
dp83848_advertise_pause_ability(esp_eth_phy_t * phy,uint32_t ability)304 static esp_err_t dp83848_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
305 {
306     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
307     esp_eth_mediator_t *eth = dp83848->eth;
308     /* Set PAUSE function ability */
309     anar_reg_t anar;
310     PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK,
311               "read ANAR failed", err);
312     if (ability) {
313         anar.asymmetric_pause = 1;
314         anar.symmetric_pause = 1;
315     } else {
316         anar.asymmetric_pause = 0;
317         anar.symmetric_pause = 0;
318     }
319     PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK,
320               "write ANAR failed", err);
321     return ESP_OK;
322 err:
323     return ESP_FAIL;
324 }
325 
dp83848_init(esp_eth_phy_t * phy)326 static esp_err_t dp83848_init(esp_eth_phy_t *phy)
327 {
328     phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
329     esp_eth_mediator_t *eth = dp83848->eth;
330     // Detect PHY address
331     if (dp83848->addr == ESP_ETH_PHY_ADDR_AUTO) {
332         PHY_CHECK(esp_eth_detect_phy_addr(eth, &dp83848->addr) == ESP_OK, "Detect PHY address failed", err);
333     }
334     /* Power on Ethernet PHY */
335     PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power control failed", err);
336     /* Reset Ethernet PHY */
337     PHY_CHECK(dp83848_reset(phy) == ESP_OK, "reset failed", err);
338     /* Check PHY ID */
339     phyidr1_reg_t id1;
340     phyidr2_reg_t id2;
341     PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
342               "read ID1 failed", err);
343     PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
344               "read ID2 failed", err);
345     PHY_CHECK(id1.oui_msb == 0x2000 && id2.oui_lsb == 0x17 && id2.vendor_model == 0x09,
346               "wrong chip ID", err);
347     return ESP_OK;
348 err:
349     return ESP_FAIL;
350 }
351 
dp83848_deinit(esp_eth_phy_t * phy)352 static esp_err_t dp83848_deinit(esp_eth_phy_t *phy)
353 {
354     /* Power off Ethernet PHY */
355     PHY_CHECK(dp83848_pwrctl(phy, false) == ESP_OK, "power control failed", err);
356     return ESP_OK;
357 err:
358     return ESP_FAIL;
359 }
360 
esp_eth_phy_new_dp83848(const eth_phy_config_t * config)361 esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config)
362 {
363     PHY_CHECK(config, "can't set phy config to null", err);
364     phy_dp83848_t *dp83848 = calloc(1, sizeof(phy_dp83848_t));
365     PHY_CHECK(dp83848, "calloc dp83848 failed", err);
366     dp83848->addr = config->phy_addr;
367     dp83848->reset_timeout_ms = config->reset_timeout_ms;
368     dp83848->link_status = ETH_LINK_DOWN;
369     dp83848->reset_gpio_num = config->reset_gpio_num;
370     dp83848->autonego_timeout_ms = config->autonego_timeout_ms;
371     dp83848->parent.reset = dp83848_reset;
372     dp83848->parent.reset_hw = dp83848_reset_hw;
373     dp83848->parent.init = dp83848_init;
374     dp83848->parent.deinit = dp83848_deinit;
375     dp83848->parent.set_mediator = dp83848_set_mediator;
376     dp83848->parent.negotiate = dp83848_negotiate;
377     dp83848->parent.get_link = dp83848_get_link;
378     dp83848->parent.pwrctl = dp83848_pwrctl;
379     dp83848->parent.get_addr = dp83848_get_addr;
380     dp83848->parent.set_addr = dp83848_set_addr;
381     dp83848->parent.advertise_pause_ability = dp83848_advertise_pause_ability;
382     dp83848->parent.del = dp83848_del;
383 
384     return &(dp83848->parent);
385 err:
386     return NULL;
387 }
388