blob: 96bb24418a0f0b30d690c0afbafc6a5fa3921070 [file] [log] [blame]
Lucien.Jheng58fa6ef2025-04-06 21:02:44 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Driver for the Airoha EN8811H 2.5 Gigabit PHY.
4 *
5 * Limitations of the EN8811H:
6 * - Only full duplex supported
7 * - Forced speed (AN off) is not supported by hardware (100Mbps)
8 *
9 * Source originated from linux air_en8811h.c
10 *
11 * Copyright (C) 2025 Airoha Technology Corp.
12 */
13#include <phy.h>
14#include <errno.h>
15#include <malloc.h>
16#include <asm/unaligned.h>
17#include <linux/iopoll.h>
18#include <dm/device_compat.h>
19#include <linux/bitops.h>
20#include <mmc.h>
21
22#define EN8811H_PHY_ID 0x03a2a411
23
24#define AIR_FW_ADDR_DM 0x00000000
25#define AIR_FW_ADDR_DSP 0x00100000
26
27#define EN8811H_MD32_DM_SIZE 0x4000
28#define EN8811H_MD32_DSP_SIZE 0x20000
29
30 #define EN8811H_FW_CTRL_1 0x0f0018
31 #define EN8811H_FW_CTRL_1_START 0x0
32 #define EN8811H_FW_CTRL_1_FINISH 0x1
33 #define EN8811H_FW_CTRL_2 0x800000
34 #define EN8811H_FW_CTRL_2_LOADING BIT(11)
35
36 /* MII Registers */
37 #define AIR_AUX_CTRL_STATUS 0x1d
38 #define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2)
39 #define AIR_AUX_CTRL_STATUS_SPEED_100 0x4
40 #define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8
41 #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc
42
43#define AIR_EXT_PAGE_ACCESS 0x1f
44#define AIR_PHY_PAGE_STANDARD 0x0000
45#define AIR_PHY_PAGE_EXTENDED_4 0x0004
46
47/* MII Registers Page 4*/
48#define AIR_BPBUS_MODE 0x10
49#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000
50#define AIR_BPBUS_MODE_ADDR_INCR BIT(15)
51#define AIR_BPBUS_WR_ADDR_HIGH 0x11
52#define AIR_BPBUS_WR_ADDR_LOW 0x12
53#define AIR_BPBUS_WR_DATA_HIGH 0x13
54#define AIR_BPBUS_WR_DATA_LOW 0x14
55#define AIR_BPBUS_RD_ADDR_HIGH 0x15
56#define AIR_BPBUS_RD_ADDR_LOW 0x16
57#define AIR_BPBUS_RD_DATA_HIGH 0x17
58#define AIR_BPBUS_RD_DATA_LOW 0x18
59
60/* Registers on MDIO_MMD_VEND1 */
61#define EN8811H_PHY_FW_STATUS 0x8009
62#define EN8811H_PHY_READY 0x02
63
64/* Registers on MDIO_MMD_VEND2 */
65#define AIR_PHY_LED_BCR 0x021
66#define AIR_PHY_LED_BCR_MODE_MASK GENMASK(1, 0)
67#define AIR_PHY_LED_BCR_TIME_TEST BIT(2)
68#define AIR_PHY_LED_BCR_CLK_EN BIT(3)
69#define AIR_PHY_LED_BCR_EXT_CTRL BIT(15)
70
71#define AIR_PHY_LED_DUR_ON 0x022
72
73#define AIR_PHY_LED_DUR_BLINK 0x023
74
75#define AIR_PHY_LED_ON(i) (0x024 + ((i) * 2))
76#define AIR_PHY_LED_ON_MASK (GENMASK(6, 0) | BIT(8))
77#define AIR_PHY_LED_ON_LINK1000 BIT(0)
78#define AIR_PHY_LED_ON_LINK100 BIT(1)
79#define AIR_PHY_LED_ON_LINK10 BIT(2)
80#define AIR_PHY_LED_ON_LINKDOWN BIT(3)
81#define AIR_PHY_LED_ON_FDX BIT(4) /* Full duplex */
82#define AIR_PHY_LED_ON_HDX BIT(5) /* Half duplex */
83#define AIR_PHY_LED_ON_FORCE_ON BIT(6)
84#define AIR_PHY_LED_ON_LINK2500 BIT(8)
85#define AIR_PHY_LED_ON_POLARITY BIT(14)
86#define AIR_PHY_LED_ON_ENABLE BIT(15)
87
88#define AIR_PHY_LED_BLINK(i) (0x025 + ((i) * 2))
89#define AIR_PHY_LED_BLINK_1000TX BIT(0)
90#define AIR_PHY_LED_BLINK_1000RX BIT(1)
91#define AIR_PHY_LED_BLINK_100TX BIT(2)
92#define AIR_PHY_LED_BLINK_100RX BIT(3)
93#define AIR_PHY_LED_BLINK_10TX BIT(4)
94#define AIR_PHY_LED_BLINK_10RX BIT(5)
95#define AIR_PHY_LED_BLINK_COLLISION BIT(6)
96#define AIR_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
97#define AIR_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
98#define AIR_PHY_LED_BLINK_FORCE_BLINK BIT(9)
99#define AIR_PHY_LED_BLINK_2500TX BIT(10)
100#define AIR_PHY_LED_BLINK_2500RX BIT(11)
101
102#define EN8811H_FW_VERSION 0x3b3c
103
104#define EN8811H_POLARITY 0xca0f8
105#define EN8811H_POLARITY_TX_NORMAL BIT(0)
106#define EN8811H_POLARITY_RX_REVERSE BIT(1)
107
108#define EN8811H_CLK_CGM 0xcf958
109#define EN8811H_CLK_CGM_CKO BIT(26)
110#define EN8811H_HWTRAP1 0xcf914
111#define EN8811H_HWTRAP1_CKO BIT(12)
112
113#define air_upper_16_bits(n) ((u16)((n) >> 16))
114#define air_lower_16_bits(n) ((u16)((n) & 0xffff))
115
116/* Led definitions */
117#define EN8811H_LED_COUNT 3
118
119/* Default LED setup:
120 * GPIO5 <-> LED0 On: Link detected
121 * GPIO4 <-> LED1 On: Link detected at 2500 and 1000 Mbps
122 * GPIO3 <-> LED2 On: Link detected at 2500 and 100 Mbps
123 */
124#define AIR_DEFAULT_TRIGGER_LED0 (AIR_PHY_LED_ON_LINK2500 | \
125 AIR_PHY_LED_ON_LINK1000 | \
126 AIR_PHY_LED_ON_LINK100)
127#define AIR_DEFAULT_TRIGGER_LED1 (AIR_PHY_LED_ON_LINK2500 | \
128 AIR_PHY_LED_ON_LINK1000 | \
129 AIR_PHY_LED_BLINK_2500TX | \
130 AIR_PHY_LED_BLINK_2500RX | \
131 AIR_PHY_LED_BLINK_1000TX | \
132 AIR_PHY_LED_BLINK_1000RX)
133#define AIR_DEFAULT_TRIGGER_LED2 (AIR_PHY_LED_ON_LINK2500 | \
134 AIR_PHY_LED_ON_LINK100 | \
135 AIR_PHY_LED_BLINK_2500TX | \
136 AIR_PHY_LED_BLINK_2500RX | \
137 AIR_PHY_LED_BLINK_100TX | \
138 AIR_PHY_LED_BLINK_100RX)
139
140struct led {
141 unsigned long rules;
142};
143
144enum {
145 AIR_PHY_LED_DUR_BLINK_32MS,
146 AIR_PHY_LED_DUR_BLINK_64MS,
147 AIR_PHY_LED_DUR_BLINK_128MS,
148 AIR_PHY_LED_DUR_BLINK_256MS,
149 AIR_PHY_LED_DUR_BLINK_512MS,
150 AIR_PHY_LED_DUR_BLINK_1024MS,
151};
152
153enum {
154 AIR_LED_DISABLE,
155 AIR_LED_ENABLE,
156};
157
158enum {
159 AIR_ACTIVE_LOW,
160 AIR_ACTIVE_HIGH,
161};
162
163enum {
164 AIR_LED_MODE_DISABLE,
165 AIR_LED_MODE_USER_DEFINE,
166};
167
168#define AIR_PHY_LED_DUR_UNIT 781
169#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS)
170
171struct en8811h_priv {
172 int firmware_version;
173 bool mcu_needs_restart;
174 struct led led[EN8811H_LED_COUNT];
175};
176
177static int air_phy_read_page(struct phy_device *phydev)
178{
179 return phy_read(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS);
180}
181
182static int air_phy_write_page(struct phy_device *phydev, int page)
183{
184 return phy_write(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS, page);
185}
186
187int air_phy_select_page(struct phy_device *phydev, int page)
188{
189 int ret, oldpage;
190
191 oldpage = air_phy_read_page(phydev);
192 if (oldpage < 0)
193 return oldpage;
194
195 if (oldpage != page) {
196 ret = air_phy_write_page(phydev, page);
197 if (ret < 0)
198 return ret;
199 }
200
201 return oldpage;
202}
203
204int air_phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
205{
206 int r;
207
208 if (oldpage >= 0) {
209 r = air_phy_write_page(phydev, oldpage);
210
211 if (ret >= 0 && r < 0)
212 ret = r;
213 } else {
214 ret = oldpage;
215 }
216
217 return ret;
218}
219
220static int air_buckpbus_reg_write(struct phy_device *phydev,
221 u32 pbus_address, u32 pbus_data)
222{
223 int ret, saved_page;
224
225 saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
226
227 if (saved_page >= 0) {
228 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
229 if (ret < 0)
230 goto restore_page;
231
232 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH,
233 air_upper_16_bits(pbus_address));
234 if (ret < 0)
235 goto restore_page;
236
237 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW,
238 air_lower_16_bits(pbus_address));
239 if (ret < 0)
240 goto restore_page;
241
242 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH,
243 air_upper_16_bits(pbus_data));
244 if (ret < 0)
245 goto restore_page;
246
247 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW,
248 air_lower_16_bits(pbus_data));
249 if (ret < 0)
250 goto restore_page;
251 }
252
253restore_page:
254 if (ret < 0)
255 printf("%s 0x%08x failed: %d\n", __func__,
256 pbus_address, ret);
257
258 return air_phy_restore_page(phydev, saved_page, ret);
259}
260
261static int air_buckpbus_reg_read(struct phy_device *phydev,
262 u32 pbus_address, u32 *pbus_data)
263{
264 int pbus_data_low, pbus_data_high;
265 int ret = 0, saved_page;
266
267 saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
268
269 if (saved_page >= 0) {
270 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
271 if (ret < 0)
272 goto restore_page;
273
274 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH,
275 air_upper_16_bits(pbus_address));
276 if (ret < 0)
277 goto restore_page;
278
279 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW,
280 air_lower_16_bits(pbus_address));
281 if (ret < 0)
282 goto restore_page;
283
284 pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH);
285 if (pbus_data_high < 0) {
286 ret = pbus_data_high;
287 goto restore_page;
288 }
289
290 pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW);
291 if (pbus_data_low < 0) {
292 ret = pbus_data_low;
293 goto restore_page;
294 }
295
296 *pbus_data = pbus_data_low | (pbus_data_high << 16);
297 }
298
299restore_page:
300 if (ret < 0)
301 printf("%s 0x%08x failed: %d\n", __func__,
302 pbus_address, ret);
303
304 return air_phy_restore_page(phydev, saved_page, ret);
305}
306
307static int air_buckpbus_reg_modify(struct phy_device *phydev,
308 u32 pbus_address, u32 mask, u32 set)
309{
310 int pbus_data_low, pbus_data_high;
311 u32 pbus_data_old, pbus_data_new;
312 int ret = 0, saved_page;
313
314 saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
315
316 if (saved_page >= 0) {
317 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
318 if (ret < 0)
319 goto restore_page;
320
321 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH,
322 air_upper_16_bits(pbus_address));
323 if (ret < 0)
324 goto restore_page;
325
326 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW,
327 air_lower_16_bits(pbus_address));
328 if (ret < 0)
329 goto restore_page;
330
331 pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH);
332 if (pbus_data_high < 0)
333 return pbus_data_high;
334
335 pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW);
336 if (pbus_data_low < 0)
337 return pbus_data_low;
338
339 pbus_data_old = pbus_data_low | (pbus_data_high << 16);
340 pbus_data_new = (pbus_data_old & ~mask) | set;
341 if (pbus_data_new == pbus_data_old)
342 return 0;
343
344 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH,
345 air_upper_16_bits(pbus_address));
346 if (ret < 0)
347 goto restore_page;
348
349 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW,
350 air_lower_16_bits(pbus_address));
351 if (ret < 0)
352 goto restore_page;
353
354 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH,
355 air_upper_16_bits(pbus_data_new));
356 if (ret < 0)
357 goto restore_page;
358
359 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW,
360 air_lower_16_bits(pbus_data_new));
361 if (ret < 0)
362 goto restore_page;
363 }
364
365restore_page:
366 if (ret < 0)
367 printf("%s 0x%08x failed: %d\n", __func__,
368 pbus_address, ret);
369
370 return air_phy_restore_page(phydev, saved_page, ret);
371}
372
373static int air_write_buf(struct phy_device *phydev, unsigned long address,
374 unsigned long array_size, const unsigned char *buffer)
375{
376 unsigned int offset;
377 int ret, saved_page;
378 u16 val;
379
380 saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
381
382 if (saved_page >= 0) {
383 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_INCR);
384 if (ret < 0)
385 goto restore_page;
386
387 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH,
388 air_upper_16_bits(address));
389 if (ret < 0)
390 goto restore_page;
391
392 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW,
393 air_lower_16_bits(address));
394 if (ret < 0)
395 goto restore_page;
396
397 for (offset = 0; offset < array_size; offset += 4) {
398 val = get_unaligned_le16(&buffer[offset + 2]);
399 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, val);
400 if (ret < 0)
401 goto restore_page;
402
403 val = get_unaligned_le16(&buffer[offset]);
404 ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, val);
405 if (ret < 0)
406 goto restore_page;
407 }
408 }
409
410restore_page:
411 if (ret < 0)
412 printf("%s 0x%08lx failed: %d\n", __func__,
413 address, ret);
414
415 return air_phy_restore_page(phydev, saved_page, ret);
416}
417
418__weak ulong *en8811h_get_fw_addr(void)
419{
420 return (ulong *)CONFIG_AIROHA_FW_ADDR;
421}
422
423static int en8811h_wait_mcu_ready(struct phy_device *phydev)
424{
425 int ret, reg_value;
426
427 /* Because of mdio-lock, may have to wait for multiple loads */
428 ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
429 EN8811H_PHY_FW_STATUS, reg_value,
430 reg_value == EN8811H_PHY_READY,
431 20000, 7500000, true);
432 if (ret) {
433 printf("MCU not ready: 0x%x\n", reg_value);
434 return -ENODEV;
435 }
436
437 return 0;
438}
439
440static int en8811h_load_firmware(struct phy_device *phydev)
441{
442 int ret;
443 char *addr = NULL;
444 struct en8811h_priv *priv = phydev->priv;
445 int dev = CONFIG_SYS_MMC_ENV_DEV;
446 u32 cnt = (CONFIG_AIROHA_MD32_DM_SIZE +
447 CONFIG_AIROHA_MD32_DSP_SIZE) / 512;
448 ulong airoha_fw_addr = (ulong)en8811h_get_fw_addr();
449 u32 blk = airoha_fw_addr / 512;
450
451 addr = malloc(CONFIG_AIROHA_MD32_DM_SIZE + CONFIG_AIROHA_MD32_DSP_SIZE);
452 if (!addr) {
453 puts("cannot allocated buffer for firmware.\n");
454 return -ENOMEM;
455 }
456
457 if (IS_ENABLED(CONFIG_PHY_AIROHA_FW_IN_MMC)) {
458 struct mmc *mmc = find_mmc_device(dev);
459
460 if (!mmc) {
461 puts("Failed to find MMC device for Airoha ucode\n");
462 goto en8811h_load_firmware_out;
463 }
464
465 printf("MMC read: dev # %u, block # %u, count %u ...\n",
466 dev, blk, cnt);
467
468 if (mmc_init(mmc)) {
469 puts("initializing MMC device failed.\n");
470 goto en8811h_load_firmware_out;
471 }
472
473 ret = mmc_set_part_conf(mmc, 1, 2, 2);
474 if (ret) {
475 puts("cannot access eMMC boot1 hw partition.\n");
476 goto en8811h_load_firmware_out;
477 }
478
479 (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
480
481 mmc_set_part_conf(mmc, 1, 1, 0);
482
483 } else {
484 puts("EN8811H firmware loading not implemented");
485 free(addr);
486 addr = NULL;
487 return -EOPNOTSUPP;
488 }
489
490 ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
491 EN8811H_FW_CTRL_1_START);
492 if (ret < 0)
493 return ret;
494
495 ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
496 EN8811H_FW_CTRL_2_LOADING,
497 EN8811H_FW_CTRL_2_LOADING);
498 if (ret < 0)
499 return ret;
500
501 ret = air_write_buf(phydev, AIR_FW_ADDR_DM, CONFIG_AIROHA_MD32_DM_SIZE, addr);
502 if (ret < 0)
503 goto en8811h_load_firmware_out;
504
505 ret = air_write_buf(phydev, AIR_FW_ADDR_DSP, CONFIG_AIROHA_MD32_DSP_SIZE,
506 addr + CONFIG_AIROHA_MD32_DM_SIZE);
507 if (ret < 0)
508 goto en8811h_load_firmware_out;
509
510 ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
511 EN8811H_FW_CTRL_2_LOADING, 0);
512 if (ret < 0)
513 return ret;
514
515 ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
516 EN8811H_FW_CTRL_1_FINISH);
517 if (ret < 0)
518 return ret;
519
520 ret = en8811h_wait_mcu_ready(phydev);
521
522 air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION,
523 &priv->firmware_version);
524 printf("MD32 firmware version: %08x\n",
525 priv->firmware_version);
526
527en8811h_load_firmware_out:
528 free(addr);
529 if (ret < 0)
530 printf("Firmware loading failed: %d\n", ret);
531
532 return ret;
533}
534
535static int en8811h_restart_mcu(struct phy_device *phydev)
536{
537 int ret;
538
539 ret = phy_write_mmd(phydev, 0x1e, 0x8009, 0x0);
540 if (ret < 0)
541 return ret;
542
543 ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
544 EN8811H_FW_CTRL_1_START);
545 if (ret < 0)
546 return ret;
547
548 return air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
549 EN8811H_FW_CTRL_1_FINISH);
550}
551
552static int air_led_hw_control_set(struct phy_device *phydev,
553 u8 index, unsigned long rules)
554{
555 struct en8811h_priv *priv = phydev->priv;
556 u16 on = 0, blink = 0;
557 int ret;
558
559 if (index >= EN8811H_LED_COUNT)
560 return -EINVAL;
561
562 on |= rules & (AIR_PHY_LED_ON_LINK100 |
563 AIR_PHY_LED_ON_LINK1000 |
564 AIR_PHY_LED_ON_LINK2500);
565
566 blink |= rules & (AIR_PHY_LED_BLINK_100TX |
567 AIR_PHY_LED_BLINK_100RX |
568 AIR_PHY_LED_BLINK_1000TX |
569 AIR_PHY_LED_BLINK_1000RX |
570 AIR_PHY_LED_BLINK_2500TX |
571 AIR_PHY_LED_BLINK_2500RX);
572
573 if (blink || on) {
574 on &= ~AIR_PHY_LED_ON_FORCE_ON;
575 blink &= ~AIR_PHY_LED_BLINK_FORCE_BLINK;
576 } else {
577 priv->led[index].rules = 0;
578 }
579
580 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index),
581 AIR_PHY_LED_ON_MASK, on);
582 if (ret < 0)
583 return ret;
584
585 return phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BLINK(index),
586 blink);
587}
588
589static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol)
590{
591 int val = 0;
592 int err;
593
594 if (index >= EN8811H_LED_COUNT)
595 return -EINVAL;
596
597 if (state == AIR_LED_ENABLE)
598 val |= AIR_PHY_LED_ON_ENABLE;
599 else
600 val &= ~AIR_PHY_LED_ON_ENABLE;
601
602 if (pol == AIR_ACTIVE_HIGH)
603 val |= AIR_PHY_LED_ON_POLARITY;
604 else
605 val &= ~AIR_PHY_LED_ON_POLARITY;
606
607 err = phy_write_mmd(phydev, 0x1f, AIR_PHY_LED_ON(index), val);
608 if (err < 0)
609 return err;
610
611 return 0;
612}
613
614static int air_leds_init(struct phy_device *phydev, int num, int dur, int mode)
615{
616 int ret, i;
617 struct en8811h_priv *priv = phydev->priv;
618
619 ret = phy_write_mmd(phydev, 0x1f, AIR_PHY_LED_DUR_BLINK, dur);
620 if (ret < 0)
621 return ret;
622
623 ret = phy_write_mmd(phydev, 0x1f, AIR_PHY_LED_DUR_ON, dur >> 1);
624 if (ret < 0)
625 return ret;
626
627 switch (mode) {
628 case AIR_LED_MODE_DISABLE:
629 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,
630 AIR_PHY_LED_BCR_EXT_CTRL |
631 AIR_PHY_LED_BCR_MODE_MASK, 0);
632 break;
633 case AIR_LED_MODE_USER_DEFINE:
634 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,
635 AIR_PHY_LED_BCR_EXT_CTRL |
636 AIR_PHY_LED_BCR_CLK_EN,
637 AIR_PHY_LED_BCR_EXT_CTRL |
638 AIR_PHY_LED_BCR_CLK_EN);
639 if (ret < 0)
640 return ret;
641 break;
642 default:
643 printf("LED mode %d is not supported\n", mode);
644 return -EINVAL;
645 }
646
647 for (i = 0; i < num; ++i) {
648 ret = air_led_init(phydev, i, AIR_LED_ENABLE, AIR_ACTIVE_HIGH);
649 if (ret < 0) {
650 printf("LED%d init failed: %d\n", i, ret);
651 return ret;
652 }
653 air_led_hw_control_set(phydev, i, priv->led[i].rules);
654 }
655
656 return 0;
657}
658
659static int en8811h_config(struct phy_device *phydev)
660{
661 ofnode node = phy_get_ofnode(phydev);
662 struct en8811h_priv *priv = phydev->priv;
663 int ret = 0;
664 u32 pbus_value = 0;
665
666 /* If restart happened in .probe(), no need to restart now */
667 if (priv->mcu_needs_restart) {
668 ret = en8811h_restart_mcu(phydev);
669 if (ret < 0)
670 return ret;
671 } else {
672 ret = en8811h_load_firmware(phydev);
673 if (ret) {
674 printf("Load firmware fail.\n");
675 return ret;
676 }
677 /* Next calls to .config() mcu needs to restart */
678 priv->mcu_needs_restart = true;
679 }
680
681 ret = phy_write_mmd(phydev, 0x1e, 0x800c, 0x0);
682 ret |= phy_write_mmd(phydev, 0x1e, 0x800d, 0x0);
683 ret |= phy_write_mmd(phydev, 0x1e, 0x800e, 0x1101);
684 ret |= phy_write_mmd(phydev, 0x1e, 0x800f, 0x0002);
685 if (ret < 0)
686 return ret;
687
688 /* Serdes polarity */
689 pbus_value = 0;
690 if (ofnode_read_bool(node, "airoha,pnswap-rx"))
691 pbus_value |= EN8811H_POLARITY_RX_REVERSE;
692 else
693 pbus_value &= ~EN8811H_POLARITY_RX_REVERSE;
694 if (ofnode_read_bool(node, "airoha,pnswap-tx"))
695 pbus_value &= ~EN8811H_POLARITY_TX_NORMAL;
696 else
697 pbus_value |= EN8811H_POLARITY_TX_NORMAL;
698 ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
699 EN8811H_POLARITY_RX_REVERSE |
700 EN8811H_POLARITY_TX_NORMAL, pbus_value);
701 if (ret < 0)
702 return ret;
703
704 ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,
705 AIR_LED_MODE_USER_DEFINE);
706 if (ret < 0) {
707 printf("Failed to disable leds: %d\n", ret);
708 return ret;
709 }
710
711 return 0;
712}
713
714static int en8811h_parse_status(struct phy_device *phydev)
715{
716 int ret = 0, reg_value;
717
718 phydev->duplex = DUPLEX_FULL;
719
720 reg_value = phy_read(phydev, MDIO_DEVAD_NONE, AIR_AUX_CTRL_STATUS);
721 if (reg_value < 0)
722 return reg_value;
723
724 switch (reg_value & AIR_AUX_CTRL_STATUS_SPEED_MASK) {
725 case AIR_AUX_CTRL_STATUS_SPEED_2500:
726 phydev->speed = SPEED_2500;
727 break;
728 case AIR_AUX_CTRL_STATUS_SPEED_1000:
729 phydev->speed = SPEED_1000;
730 break;
731 case AIR_AUX_CTRL_STATUS_SPEED_100:
732 phydev->speed = SPEED_100;
733 break;
734 default:
735 printf("Auto-neg error, defaulting to 100M/FD\n");
736 phydev->speed = SPEED_100;
737 break;
738 }
739
740 return ret;
741}
742
743static int en8811h_startup(struct phy_device *phydev)
744{
745 int ret = 0;
746
747 ret = genphy_update_link(phydev);
748 if (ret)
749 return ret;
750
751 return en8811h_parse_status(phydev);
752}
753
754static int en8811h_probe(struct phy_device *phydev)
755{
756 struct en8811h_priv *priv;
757
758 priv = malloc(sizeof(*priv));
759 if (!priv)
760 return -ENOMEM;
761 memset(priv, 0, sizeof(*priv));
762
763 priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0;
764 priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1;
765 priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2;
766
767 /* mcu has just restarted after firmware load */
768 priv->mcu_needs_restart = false;
769
770 phydev->priv = priv;
771
772 return 0;
773}
774
775U_BOOT_PHY_DRIVER(en8811h) = {
776 .name = "Airoha EN8811H",
777 .uid = EN8811H_PHY_ID,
778 .mask = 0x0ffffff0,
779 .config = &en8811h_config,
780 .probe = &en8811h_probe,
781 .startup = &en8811h_startup,
782 .shutdown = &genphy_shutdown,
783};