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