1 From cedafee9ff39d13aaf8b80361b673445a85f117e Mon Sep 17 00:00:00 2001
2 From: Weijie Gao <weijie.gao@mediatek.com>
3 Date: Fri, 10 Jan 2025 16:41:24 +0800
4 Subject: [PATCH 3/3] net: mediatek: add support for Airoha AN8855 ethernet
7 Airoha AN8855 is a 5-port gigabit switch with a 2.5G HSGMII CPU port
9 Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
11 drivers/net/mtk_eth/Kconfig | 4 +
12 drivers/net/mtk_eth/Makefile | 1 +
13 drivers/net/mtk_eth/an8855.c | 1096 ++++++++++++++++++++++++++++++++++
14 3 files changed, 1101 insertions(+)
15 create mode 100644 drivers/net/mtk_eth/an8855.c
17 --- a/drivers/net/mtk_eth/Kconfig
18 +++ b/drivers/net/mtk_eth/Kconfig
19 @@ -32,4 +32,8 @@ config MTK_ETH_SWITCH_MT7988
20 depends on TARGET_MT7988
23 +config MTK_ETH_SWITCH_AN8855
24 + bool "Support for Airoha AN8855 ethernet switch"
25 + default y if TARGET_MT7981 || TARGET_MT7987
28 --- a/drivers/net/mtk_eth/Makefile
29 +++ b/drivers/net/mtk_eth/Makefile
30 @@ -7,3 +7,4 @@ obj-y += mtk_eth.o
31 obj-$(CONFIG_MTK_ETH_SWITCH_MT7530) += mt753x.o mt7530.o
32 obj-$(CONFIG_MTK_ETH_SWITCH_MT7531) += mt753x.o mt7531.o
33 obj-$(CONFIG_MTK_ETH_SWITCH_MT7988) += mt753x.o mt7988.o
34 +obj-$(CONFIG_MTK_ETH_SWITCH_AN8855) += an8855.o
36 +++ b/drivers/net/mtk_eth/an8855.c
38 +// SPDX-License-Identifier: GPL-2.0
40 + * Copyright (C) 2025 MediaTek Inc.
42 + * Author: Neal Yen <neal.yen@mediatek.com>
43 + * Author: Weijie Gao <weijie.gao@mediatek.com>
48 +#include <linux/bitops.h>
49 +#include <linux/delay.h>
50 +#include <linux/mdio.h>
51 +#include <linux/mii.h>
54 +/* AN8855 Register Definitions */
55 +#define AN8855_SYS_CTRL_REG 0x100050c0
56 +#define AN8855_SW_SYS_RST BIT(31)
58 +#define AN8855_PMCR_REG(p) (0x10210000 + (p) * 0x200)
59 +#define AN8855_FORCE_MODE_LNK BIT(31)
60 +#define AN8855_FORCE_MODE 0xb31593f0
62 +#define AN8855_PORT_CTRL_BASE (0x10208000)
63 +#define AN8855_PORT_CTRL_REG(p, r) (AN8855_PORT_CTRL_BASE + (p) * 0x200 + (r))
65 +#define AN8855_PORTMATRIX_REG(p) AN8855_PORT_CTRL_REG(p, 0x44)
67 +#define AN8855_PVC(p) AN8855_PORT_CTRL_REG(p, 0x10)
68 +#define AN8855_STAG_VPID_S 16
69 +#define AN8855_STAG_VPID_M 0xffff0000
70 +#define AN8855_VLAN_ATTR_S 6
71 +#define AN8855_VLAN_ATTR_M 0xc0
73 +#define VLAN_ATTR_USER 0
75 +#define AN8855_INT_MASK 0x100050F0
76 +#define AN8855_INT_SYS_BIT BIT(15)
78 +#define AN8855_RG_CLK_CPU_ICG 0x10005034
79 +#define AN8855_MCU_ENABLE BIT(3)
81 +#define AN8855_RG_TIMER_CTL 0x1000a100
82 +#define AN8855_WDOG_ENABLE BIT(25)
84 +#define AN8855_CKGCR 0x10213e1c
86 +#define AN8855_SCU_BASE 0x10000000
87 +#define AN8855_RG_RGMII_TXCK_C (AN8855_SCU_BASE + 0x1d0)
88 +#define AN8855_RG_GPIO_LED_MODE (AN8855_SCU_BASE + 0x0054)
89 +#define AN8855_RG_GPIO_LED_SEL(i) (AN8855_SCU_BASE + (0x0058 + ((i) * 4)))
90 +#define AN8855_RG_INTB_MODE (AN8855_SCU_BASE + 0x0080)
91 +#define AN8855_RG_GDMP_RAM (AN8855_SCU_BASE + 0x10000)
92 +#define AN8855_RG_GPIO_L_INV (AN8855_SCU_BASE + 0x0010)
93 +#define AN8855_RG_GPIO_CTRL (AN8855_SCU_BASE + 0xa300)
94 +#define AN8855_RG_GPIO_DATA (AN8855_SCU_BASE + 0xa304)
95 +#define AN8855_RG_GPIO_OE (AN8855_SCU_BASE + 0xa314)
97 +#define AN8855_HSGMII_AN_CSR_BASE 0x10220000
98 +#define AN8855_SGMII_REG_AN0 (AN8855_HSGMII_AN_CSR_BASE + 0x000)
99 +#define AN8855_SGMII_REG_AN_13 (AN8855_HSGMII_AN_CSR_BASE + 0x034)
100 +#define AN8855_SGMII_REG_AN_FORCE_CL37 (AN8855_HSGMII_AN_CSR_BASE + 0x060)
102 +#define AN8855_HSGMII_CSR_PCS_BASE 0x10220000
103 +#define AN8855_RG_HSGMII_PCS_CTROL_1 (AN8855_HSGMII_CSR_PCS_BASE + 0xa00)
104 +#define AN8855_RG_AN_SGMII_MODE_FORCE (AN8855_HSGMII_CSR_PCS_BASE + 0xa24)
106 +#define AN8855_MULTI_SGMII_CSR_BASE 0x10224000
107 +#define AN8855_SGMII_STS_CTRL_0 (AN8855_MULTI_SGMII_CSR_BASE + 0x018)
108 +#define AN8855_MSG_RX_CTRL_0 (AN8855_MULTI_SGMII_CSR_BASE + 0x100)
109 +#define AN8855_MSG_RX_LIK_STS_0 (AN8855_MULTI_SGMII_CSR_BASE + 0x514)
110 +#define AN8855_MSG_RX_LIK_STS_2 (AN8855_MULTI_SGMII_CSR_BASE + 0x51c)
111 +#define AN8855_PHY_RX_FORCE_CTRL_0 (AN8855_MULTI_SGMII_CSR_BASE + 0x520)
113 +#define AN8855_XFI_CSR_PCS_BASE 0x10225000
114 +#define AN8855_RG_USXGMII_AN_CONTROL_0 (AN8855_XFI_CSR_PCS_BASE + 0xbf8)
116 +#define AN8855_MULTI_PHY_RA_CSR_BASE 0x10226000
117 +#define AN8855_RG_RATE_ADAPT_CTRL_0 (AN8855_MULTI_PHY_RA_CSR_BASE + 0x000)
118 +#define AN8855_RATE_ADP_P0_CTRL_0 (AN8855_MULTI_PHY_RA_CSR_BASE + 0x100)
119 +#define AN8855_MII_RA_AN_ENABLE (AN8855_MULTI_PHY_RA_CSR_BASE + 0x300)
121 +#define AN8855_QP_DIG_CSR_BASE 0x1022a000
122 +#define AN8855_QP_CK_RST_CTRL_4 (AN8855_QP_DIG_CSR_BASE + 0x310)
123 +#define AN8855_QP_DIG_MODE_CTRL_0 (AN8855_QP_DIG_CSR_BASE + 0x324)
124 +#define AN8855_QP_DIG_MODE_CTRL_1 (AN8855_QP_DIG_CSR_BASE + 0x330)
126 +#define AN8855_QP_PMA_TOP_BASE 0x1022e000
127 +#define AN8855_PON_RXFEDIG_CTRL_0 (AN8855_QP_PMA_TOP_BASE + 0x100)
128 +#define AN8855_PON_RXFEDIG_CTRL_9 (AN8855_QP_PMA_TOP_BASE + 0x124)
130 +#define AN8855_SS_LCPLL_PWCTL_SETTING_2 (AN8855_QP_PMA_TOP_BASE + 0x208)
131 +#define AN8855_SS_LCPLL_TDC_FLT_2 (AN8855_QP_PMA_TOP_BASE + 0x230)
132 +#define AN8855_SS_LCPLL_TDC_FLT_5 (AN8855_QP_PMA_TOP_BASE + 0x23c)
133 +#define AN8855_SS_LCPLL_TDC_PCW_1 (AN8855_QP_PMA_TOP_BASE + 0x248)
134 +#define AN8855_INTF_CTRL_8 (AN8855_QP_PMA_TOP_BASE + 0x320)
135 +#define AN8855_INTF_CTRL_9 (AN8855_QP_PMA_TOP_BASE + 0x324)
136 +#define AN8855_PLL_CTRL_0 (AN8855_QP_PMA_TOP_BASE + 0x400)
137 +#define AN8855_PLL_CTRL_2 (AN8855_QP_PMA_TOP_BASE + 0x408)
138 +#define AN8855_PLL_CTRL_3 (AN8855_QP_PMA_TOP_BASE + 0x40c)
139 +#define AN8855_PLL_CTRL_4 (AN8855_QP_PMA_TOP_BASE + 0x410)
140 +#define AN8855_PLL_CK_CTRL_0 (AN8855_QP_PMA_TOP_BASE + 0x414)
141 +#define AN8855_RX_DLY_0 (AN8855_QP_PMA_TOP_BASE + 0x614)
142 +#define AN8855_RX_CTRL_2 (AN8855_QP_PMA_TOP_BASE + 0x630)
143 +#define AN8855_RX_CTRL_5 (AN8855_QP_PMA_TOP_BASE + 0x63c)
144 +#define AN8855_RX_CTRL_6 (AN8855_QP_PMA_TOP_BASE + 0x640)
145 +#define AN8855_RX_CTRL_7 (AN8855_QP_PMA_TOP_BASE + 0x644)
146 +#define AN8855_RX_CTRL_8 (AN8855_QP_PMA_TOP_BASE + 0x648)
147 +#define AN8855_RX_CTRL_26 (AN8855_QP_PMA_TOP_BASE + 0x690)
148 +#define AN8855_RX_CTRL_42 (AN8855_QP_PMA_TOP_BASE + 0x6d0)
150 +#define AN8855_QP_ANA_CSR_BASE 0x1022f000
151 +#define AN8855_RG_QP_RX_DAC_EN (AN8855_QP_ANA_CSR_BASE + 0x00)
152 +#define AN8855_RG_QP_RXAFE_RESERVE (AN8855_QP_ANA_CSR_BASE + 0x04)
153 +#define AN8855_RG_QP_CDR_LPF_MJV_LIM (AN8855_QP_ANA_CSR_BASE + 0x0c)
154 +#define AN8855_RG_QP_CDR_LPF_SETVALUE (AN8855_QP_ANA_CSR_BASE + 0x14)
155 +#define AN8855_RG_QP_CDR_PR_CKREF_DIV1 (AN8855_QP_ANA_CSR_BASE + 0x18)
156 +#define AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE (AN8855_QP_ANA_CSR_BASE + 0x1c)
157 +#define AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF (AN8855_QP_ANA_CSR_BASE + 0x20)
158 +#define AN8855_RG_QP_TX_MODE_16B_EN (AN8855_QP_ANA_CSR_BASE + 0x28)
159 +#define AN8855_RG_QP_PLL_IPLL_DIG_PWR_SEL (AN8855_QP_ANA_CSR_BASE + 0x3c)
160 +#define AN8855_RG_QP_PLL_SDM_ORD (AN8855_QP_ANA_CSR_BASE + 0x40)
162 +#define AN8855_ETHER_SYS_BASE 0x1028c800
163 +#define RG_GPHY_AFE_PWD (AN8855_ETHER_SYS_BASE + 0x40)
165 +#define AN8855_PKG_SEL 0x10000094
166 +#define PAG_SEL_AN8855H 0x2
168 +/* PHY LED Register bitmap of define */
169 +#define PHY_LED_CTRL_SELECT 0x3e8
170 +#define PHY_SINGLE_LED_ON_CTRL(i) (0x3e0 + ((i) * 2))
171 +#define PHY_SINGLE_LED_BLK_CTRL(i) (0x3e1 + ((i) * 2))
172 +#define PHY_SINGLE_LED_ON_DUR(i) (0x3e9 + ((i) * 2))
173 +#define PHY_SINGLE_LED_BLK_DUR(i) (0x3ea + ((i) * 2))
175 +#define PHY_PMA_CTRL (0x340)
177 +#define PHY_DEV1F 0x1f
179 +#define PHY_LED_ON_CTRL(i) (0x24 + ((i) * 2))
180 +#define LED_ON_EN (1 << 15)
181 +#define LED_ON_POL (1 << 14)
182 +#define LED_ON_EVT_MASK (0x7f)
185 +#define LED_ON_EVT_FORCE (1 << 6)
186 +#define LED_ON_EVT_LINK_HD (1 << 5)
187 +#define LED_ON_EVT_LINK_FD (1 << 4)
188 +#define LED_ON_EVT_LINK_DOWN (1 << 3)
189 +#define LED_ON_EVT_LINK_10M (1 << 2)
190 +#define LED_ON_EVT_LINK_100M (1 << 1)
191 +#define LED_ON_EVT_LINK_1000M (1 << 0)
193 +#define PHY_LED_BLK_CTRL(i) (0x25 + ((i) * 2))
194 +#define LED_BLK_EVT_MASK (0x3ff)
195 +/* LED Blinking Event */
196 +#define LED_BLK_EVT_FORCE (1 << 9)
197 +#define LED_BLK_EVT_10M_RX_ACT (1 << 5)
198 +#define LED_BLK_EVT_10M_TX_ACT (1 << 4)
199 +#define LED_BLK_EVT_100M_RX_ACT (1 << 3)
200 +#define LED_BLK_EVT_100M_TX_ACT (1 << 2)
201 +#define LED_BLK_EVT_1000M_RX_ACT (1 << 1)
202 +#define LED_BLK_EVT_1000M_TX_ACT (1 << 0)
204 +#define PHY_LED_BCR (0x21)
205 +#define LED_BCR_EXT_CTRL (1 << 15)
206 +#define LED_BCR_CLK_EN (1 << 3)
207 +#define LED_BCR_TIME_TEST (1 << 2)
208 +#define LED_BCR_MODE_MASK (3)
209 +#define LED_BCR_MODE_DISABLE (0)
211 +#define PHY_LED_ON_DUR (0x22)
212 +#define LED_ON_DUR_MASK (0xffff)
214 +#define PHY_LED_BLK_DUR (0x23)
215 +#define LED_BLK_DUR_MASK (0xffff)
217 +#define PHY_LED_BLINK_DUR_CTRL (0x720)
219 +/* Definition of LED */
220 +#define LED_ON_EVENT (LED_ON_EVT_LINK_1000M | \
221 + LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M |\
222 + LED_ON_EVT_LINK_HD | LED_ON_EVT_LINK_FD)
224 +#define LED_BLK_EVENT (LED_BLK_EVT_1000M_TX_ACT | \
225 + LED_BLK_EVT_1000M_RX_ACT | \
226 + LED_BLK_EVT_100M_TX_ACT | \
227 + LED_BLK_EVT_100M_RX_ACT | \
228 + LED_BLK_EVT_10M_TX_ACT | \
229 + LED_BLK_EVT_10M_RX_ACT)
231 +#define LED_FREQ AIR_LED_BLK_DUR_64M
233 +#define AN8855_NUM_PHYS 5
234 +#define AN8855_NUM_PORTS 6
235 +#define AN8855_PHY_ADDR(base, addr) (((base) + (addr)) & 0x1f)
237 +/* PHY LED Register bitmap of define */
238 +#define PHY_LED_CTRL_SELECT 0x3e8
239 +#define PHY_SINGLE_LED_ON_CTRL(i) (0x3e0 + ((i) * 2))
240 +#define PHY_SINGLE_LED_BLK_CTRL(i) (0x3e1 + ((i) * 2))
241 +#define PHY_SINGLE_LED_ON_DUR(i) (0x3e9 + ((i) * 2))
242 +#define PHY_SINGLE_LED_BLK_DUR(i) (0x3ea + ((i) * 2))
245 +enum an8855_led_blk_dur {
246 + AIR_LED_BLK_DUR_32M,
247 + AIR_LED_BLK_DUR_64M,
248 + AIR_LED_BLK_DUR_128M,
249 + AIR_LED_BLK_DUR_256M,
250 + AIR_LED_BLK_DUR_512M,
251 + AIR_LED_BLK_DUR_1024M,
252 + AIR_LED_BLK_DUR_LAST
255 +enum an8855_led_polarity {
260 +enum an8855_led_mode {
261 + AN8855_LED_MODE_DISABLE,
262 + AN8855_LED_MODE_USER_DEFINE,
263 + AN8855_LED_MODE_LAST
290 +struct an8855_led_cfg {
299 +struct an8855_switch_priv {
300 + struct mtk_eth_switch_priv epriv;
301 + struct mii_dev *mdio_bus;
305 +/* AN8855 Reference Board */
306 +static const struct an8855_led_cfg led_cfg[] = {
307 +/*************************************************************************
308 + * Enable, LED idx, LED Polarity, LED ON event, LED Blink event LED Freq
309 + *************************************************************************
312 + {1, P4_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
314 + {1, P4_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
316 + {1, P0_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
318 + {1, P0_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
320 + {1, P1_LED0, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
322 + {1, P1_LED1, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
324 + {0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
326 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
328 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
330 + {1, P2_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
332 + {1, P2_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
334 + {1, P3_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
336 + {1, P3_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
338 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
340 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
342 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
344 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
346 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
348 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
350 + {0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
352 + {0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
355 +static int __an8855_reg_read(struct mtk_eth_priv *priv, u8 phy_base, u32 reg, u32 *data)
357 + int ret, low_word, high_word;
359 + ret = mtk_mii_write(priv, phy_base, 0x1f, 0x4);
363 + ret = mtk_mii_write(priv, phy_base, 0x10, 0);
367 + ret = mtk_mii_write(priv, phy_base, 0x15, ((reg >> 16) & 0xFFFF));
371 + ret = mtk_mii_write(priv, phy_base, 0x16, (reg & 0xFFFF));
375 + low_word = mtk_mii_read(priv, phy_base, 0x18);
379 + high_word = mtk_mii_read(priv, phy_base, 0x17);
383 + ret = mtk_mii_write(priv, phy_base, 0x1f, 0);
387 + ret = mtk_mii_write(priv, phy_base, 0x10, 0);
392 + *data = ((u32)high_word << 16) | (low_word & 0xffff);
397 +static int an8855_reg_read(struct an8855_switch_priv *priv, u32 reg, u32 *data)
399 + return __an8855_reg_read(priv->epriv.eth, priv->phy_base, reg, data);
402 +static int an8855_reg_write(struct an8855_switch_priv *priv, u32 reg, u32 data)
406 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x1f, 0x4);
410 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x10, 0);
414 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x11,
415 + ((reg >> 16) & 0xFFFF));
419 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x12,
424 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x13,
425 + ((data >> 16) & 0xFFFF));
429 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x14,
434 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x1f, 0);
438 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x10, 0);
445 +static int an8855_phy_cl45_read(struct an8855_switch_priv *priv, int port,
446 + int devad, int regnum, u16 *data)
448 + u16 phy_addr = AN8855_PHY_ADDR(priv->phy_base, port);
450 + *data = mtk_mmd_ind_read(priv->epriv.eth, phy_addr, devad, regnum);
455 +static int an8855_phy_cl45_write(struct an8855_switch_priv *priv, int port,
456 + int devad, int regnum, u16 data)
458 + u16 phy_addr = AN8855_PHY_ADDR(priv->phy_base, port);
460 + mtk_mmd_ind_write(priv->epriv.eth, phy_addr, devad, regnum, data);
465 +static int an8855_port_sgmii_init(struct an8855_switch_priv *priv, u32 port)
470 + printf("an8855: port %d is not a SGMII port\n", port);
475 + an8855_reg_read(priv, AN8855_QP_DIG_MODE_CTRL_1, &val);
476 + val &= ~(0x3 << 2);
478 + an8855_reg_write(priv, AN8855_QP_DIG_MODE_CTRL_1, val);
481 + an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
482 + val &= ~(0x3 << 0);
484 + val &= ~(0x7 << 2);
486 + val &= ~GENMASK(7, 6);
487 + val &= ~(0x7 << 8);
490 + val &= ~GENMASK(13, 12);
491 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
494 + an8855_reg_read(priv, AN8855_PLL_CTRL_4, &val);
496 + an8855_reg_write(priv, AN8855_PLL_CTRL_4, val);
498 + an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
500 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
503 + an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
504 + val &= ~(0xf << 16);
505 + val |= (0x6 << 16);
506 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
509 + an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
510 + val &= ~(0x3 << 20);
511 + val |= (0x1 << 20);
512 + val &= ~(0x3 << 24);
513 + val |= (0x1 << 24);
515 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
517 + /* PLL - POSTDIV */
518 + an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
522 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
525 + an8855_reg_read(priv, AN8855_PLL_CTRL_4, &val);
526 + val &= ~GENMASK(4, 3);
527 + an8855_reg_write(priv, AN8855_PLL_CTRL_4, val);
529 + an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
531 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
533 + an8855_reg_read(priv, AN8855_SS_LCPLL_PWCTL_SETTING_2, &val);
534 + val &= ~(0x3 << 16);
535 + val |= (0x1 << 16);
536 + an8855_reg_write(priv, AN8855_SS_LCPLL_PWCTL_SETTING_2, val);
538 + an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_FLT_2, 0x7a000000);
539 + an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_PCW_1, 0x7a000000);
541 + an8855_reg_read(priv, AN8855_SS_LCPLL_TDC_FLT_5, &val);
543 + an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_FLT_5, val);
545 + an8855_reg_read(priv, AN8855_PLL_CK_CTRL_0, &val);
547 + an8855_reg_write(priv, AN8855_PLL_CK_CTRL_0, val);
550 + an8855_reg_read(priv, AN8855_PLL_CTRL_3, &val);
551 + val &= ~GENMASK(15, 0);
552 + an8855_reg_write(priv, AN8855_PLL_CTRL_3, val);
554 + an8855_reg_read(priv, AN8855_PLL_CTRL_4, &val);
555 + val &= ~GENMASK(1, 0);
556 + an8855_reg_write(priv, AN8855_PLL_CTRL_4, val);
558 + an8855_reg_read(priv, AN8855_PLL_CTRL_3, &val);
559 + val &= ~GENMASK(31, 16);
560 + an8855_reg_write(priv, AN8855_PLL_CTRL_3, val);
563 + an8855_reg_read(priv, AN8855_PLL_CK_CTRL_0, &val);
565 + an8855_reg_write(priv, AN8855_PLL_CK_CTRL_0, val);
567 + an8855_reg_read(priv, AN8855_RG_QP_PLL_SDM_ORD, &val);
570 + an8855_reg_write(priv, AN8855_RG_QP_PLL_SDM_ORD, val);
572 + an8855_reg_read(priv, AN8855_RG_QP_RX_DAC_EN, &val);
573 + val &= ~(0x3 << 16);
574 + val |= (0x2 << 16);
575 + an8855_reg_write(priv, AN8855_RG_QP_RX_DAC_EN, val);
577 + /* TCL Disable (only for Co-SIM) */
578 + an8855_reg_read(priv, AN8855_PON_RXFEDIG_CTRL_0, &val);
580 + an8855_reg_write(priv, AN8855_PON_RXFEDIG_CTRL_0, val);
583 + an8855_reg_read(priv, AN8855_RG_QP_TX_MODE_16B_EN, &val);
585 + val &= ~(0xffff << 16);
586 + val |= (0x4 << 16);
587 + an8855_reg_write(priv, AN8855_RG_QP_TX_MODE_16B_EN, val);
590 + an8855_reg_read(priv, AN8855_RG_QP_RXAFE_RESERVE, &val);
592 + an8855_reg_write(priv, AN8855_RG_QP_RXAFE_RESERVE, val);
594 + an8855_reg_read(priv, AN8855_RG_QP_CDR_LPF_MJV_LIM, &val);
595 + val &= ~(0x3 << 4);
597 + an8855_reg_write(priv, AN8855_RG_QP_CDR_LPF_MJV_LIM, val);
599 + an8855_reg_read(priv, AN8855_RG_QP_CDR_LPF_SETVALUE, &val);
600 + val &= ~(0xf << 25);
601 + val |= (0x1 << 25);
602 + val &= ~(0x7 << 29);
603 + val |= (0x3 << 29);
604 + an8855_reg_write(priv, AN8855_RG_QP_CDR_LPF_SETVALUE, val);
606 + an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, &val);
607 + val &= ~(0x1f << 8);
609 + an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, val);
611 + an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, &val);
612 + val &= ~(0x3f << 0);
613 + val |= (0x19 << 0);
615 + an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
617 + an8855_reg_read(priv, AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF, &val);
618 + val &= ~(0x7f << 6);
619 + val |= (0x21 << 6);
620 + val &= ~(0x3 << 16);
621 + val |= (0x2 << 16);
623 + an8855_reg_write(priv, AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF, val);
625 + an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, &val);
627 + an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
629 + an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, &val);
630 + val &= ~(0x7 << 24);
631 + val |= (0x4 << 24);
632 + an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, val);
634 + an8855_reg_read(priv, AN8855_PLL_CTRL_0, &val);
636 + an8855_reg_write(priv, AN8855_PLL_CTRL_0, val);
638 + an8855_reg_read(priv, AN8855_RX_CTRL_26, &val);
641 + an8855_reg_write(priv, AN8855_RX_CTRL_26, val);
643 + an8855_reg_read(priv, AN8855_RX_DLY_0, &val);
644 + val &= ~(0xff << 0);
645 + val |= (0x6f << 0);
646 + val |= GENMASK(13, 8);
647 + an8855_reg_write(priv, AN8855_RX_DLY_0, val);
649 + an8855_reg_read(priv, AN8855_RX_CTRL_42, &val);
650 + val &= ~(0x1fff << 0);
651 + val |= (0x150 << 0);
652 + an8855_reg_write(priv, AN8855_RX_CTRL_42, val);
654 + an8855_reg_read(priv, AN8855_RX_CTRL_2, &val);
655 + val &= ~(0x1fff << 16);
656 + val |= (0x150 << 16);
657 + an8855_reg_write(priv, AN8855_RX_CTRL_2, val);
659 + an8855_reg_read(priv, AN8855_PON_RXFEDIG_CTRL_9, &val);
660 + val &= ~(0x7 << 0);
662 + an8855_reg_write(priv, AN8855_PON_RXFEDIG_CTRL_9, val);
664 + an8855_reg_read(priv, AN8855_RX_CTRL_8, &val);
665 + val &= ~(0xfff << 16);
666 + val |= (0x200 << 16);
667 + val &= ~(0x7fff << 14);
668 + val |= (0xfff << 14);
669 + an8855_reg_write(priv, AN8855_RX_CTRL_8, val);
671 + /* Frequency memter */
672 + an8855_reg_read(priv, AN8855_RX_CTRL_5, &val);
673 + val &= ~(0xfffff << 10);
674 + val |= (0x10 << 10);
675 + an8855_reg_write(priv, AN8855_RX_CTRL_5, val);
677 + an8855_reg_read(priv, AN8855_RX_CTRL_6, &val);
678 + val &= ~(0xfffff << 0);
679 + val |= (0x64 << 0);
680 + an8855_reg_write(priv, AN8855_RX_CTRL_6, val);
682 + an8855_reg_read(priv, AN8855_RX_CTRL_7, &val);
683 + val &= ~(0xfffff << 0);
684 + val |= (0x2710 << 0);
685 + an8855_reg_write(priv, AN8855_RX_CTRL_7, val);
688 + an8855_reg_read(priv, AN8855_RG_HSGMII_PCS_CTROL_1, &val);
690 + an8855_reg_write(priv, AN8855_RG_HSGMII_PCS_CTROL_1, val);
692 + /* Rate Adaption */
693 + an8855_reg_read(priv, AN8855_RATE_ADP_P0_CTRL_0, &val);
695 + an8855_reg_write(priv, AN8855_RATE_ADP_P0_CTRL_0, val);
697 + an8855_reg_read(priv, AN8855_RG_RATE_ADAPT_CTRL_0, &val);
700 + val |= GENMASK(27, 26);
701 + an8855_reg_write(priv, AN8855_RG_RATE_ADAPT_CTRL_0, val);
704 + an8855_reg_read(priv, AN8855_SGMII_REG_AN0, &val);
706 + an8855_reg_write(priv, AN8855_SGMII_REG_AN0, val);
709 + an8855_reg_read(priv, AN8855_SGMII_STS_CTRL_0, &val);
711 + val |= GENMASK(5, 4);
712 + an8855_reg_write(priv, AN8855_SGMII_STS_CTRL_0, val);
714 + /* bypass flow control to MAC */
715 + an8855_reg_write(priv, AN8855_MSG_RX_LIK_STS_0, 0x01010107);
716 + an8855_reg_write(priv, AN8855_MSG_RX_LIK_STS_2, 0x00000EEF);
721 +static void an8855_led_set_usr_def(struct an8855_switch_priv *priv, u8 entity,
722 + enum an8855_led_polarity pol, u16 on_evt,
723 + u16 blk_evt, u8 led_freq)
727 + if (pol == LED_HIGH)
728 + on_evt |= LED_ON_POL;
730 + on_evt &= ~LED_ON_POL;
733 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
734 + PHY_SINGLE_LED_ON_CTRL(entity % 4),
735 + on_evt | LED_ON_EN);
737 + /* LED blink event */
738 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
739 + PHY_SINGLE_LED_BLK_CTRL(entity % 4),
743 + switch (led_freq) {
744 + case AIR_LED_BLK_DUR_32M:
748 + case AIR_LED_BLK_DUR_64M:
752 + case AIR_LED_BLK_DUR_128M:
756 + case AIR_LED_BLK_DUR_256M:
757 + cl45_data = 0x186a;
760 + case AIR_LED_BLK_DUR_512M:
761 + cl45_data = 0x30d4;
764 + case AIR_LED_BLK_DUR_1024M:
765 + cl45_data = 0x61a8;
773 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
774 + PHY_SINGLE_LED_BLK_DUR(entity % 4),
777 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
778 + PHY_SINGLE_LED_ON_DUR(entity % 4),
781 + /* Disable DATA & BAD_SSD for port LED blink behavior */
782 + cl45_data = mtk_mmd_ind_read(priv->epriv.eth, (entity / 4), 0x1e, PHY_PMA_CTRL);
783 + cl45_data &= ~BIT(0);
784 + cl45_data &= ~BIT(15);
785 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e, PHY_PMA_CTRL, cl45_data);
788 +static int an8855_led_set_mode(struct an8855_switch_priv *priv, u8 mode)
792 + an8855_phy_cl45_read(priv, 0, 0x1f, PHY_LED_BCR, &cl45_data);
795 + case AN8855_LED_MODE_DISABLE:
796 + cl45_data &= ~LED_BCR_EXT_CTRL;
797 + cl45_data &= ~LED_BCR_MODE_MASK;
798 + cl45_data |= LED_BCR_MODE_DISABLE;
801 + case AN8855_LED_MODE_USER_DEFINE:
802 + cl45_data |= LED_BCR_EXT_CTRL;
803 + cl45_data |= LED_BCR_CLK_EN;
807 + printf("an8855: LED mode%d is not supported!\n", mode);
811 + an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BCR, cl45_data);
816 +static int an8855_led_set_state(struct an8855_switch_priv *priv, u8 entity,
821 + /* Change to per port contorl */
822 + an8855_phy_cl45_read(priv, (entity / 4), 0x1e, PHY_LED_CTRL_SELECT,
826 + cl45_data |= (1 << (entity % 4));
828 + cl45_data &= ~(1 << (entity % 4));
830 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e, PHY_LED_CTRL_SELECT,
833 + /* LED enable setting */
834 + an8855_phy_cl45_read(priv, (entity / 4), 0x1e,
835 + PHY_SINGLE_LED_ON_CTRL(entity % 4), &cl45_data);
838 + cl45_data |= LED_ON_EN;
840 + cl45_data &= ~LED_ON_EN;
842 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
843 + PHY_SINGLE_LED_ON_CTRL(entity % 4), cl45_data);
848 +static int an8855_led_init(struct an8855_switch_priv *priv)
850 + u32 val, id, tmp_id = 0;
853 + ret = an8855_led_set_mode(priv, AN8855_LED_MODE_USER_DEFINE);
855 + printf("an8855: led_set_mode failed with %d!\n", ret);
859 + for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
860 + ret = an8855_led_set_state(priv, led_cfg[id].phy_led_idx,
863 + printf("an8855: led_set_state failed with %d!\n", ret);
867 + if (led_cfg[id].en == 1) {
868 + an8855_led_set_usr_def(priv,
869 + led_cfg[id].phy_led_idx,
871 + led_cfg[id].on_cfg,
872 + led_cfg[id].blk_cfg,
873 + led_cfg[id].led_freq);
877 + /* Setting for System LED & Loop LED */
878 + an8855_reg_write(priv, AN8855_RG_GPIO_OE, 0x0);
879 + an8855_reg_write(priv, AN8855_RG_GPIO_CTRL, 0x0);
880 + an8855_reg_write(priv, AN8855_RG_GPIO_L_INV, 0);
882 + an8855_reg_write(priv, AN8855_RG_GPIO_CTRL, 0x1001);
883 + an8855_reg_read(priv, AN8855_RG_GPIO_DATA, &val);
884 + val |= GENMASK(3, 1);
887 + an8855_reg_write(priv, AN8855_RG_GPIO_DATA, val);
889 + an8855_reg_read(priv, AN8855_RG_GPIO_OE, &val);
891 + an8855_reg_write(priv, AN8855_RG_GPIO_OE, val);
893 + /* Mapping between GPIO & LED */
895 + for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
896 + /* Skip GPIO6, due to GPIO6 does not support PORT LED */
900 + if (led_cfg[id].en == 1) {
902 + val |= led_cfg[id].phy_led_idx << ((id % 4) * 8);
904 + val |= led_cfg[id].phy_led_idx << (((id - 1) % 4) * 8);
912 + if ((tmp_id % 4) == 0x3) {
913 + an8855_reg_write(priv,
914 + AN8855_RG_GPIO_LED_SEL(tmp_id / 4),
920 + /* Turn on LAN LED mode */
922 + for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
923 + if (led_cfg[id].en == 1)
926 + an8855_reg_write(priv, AN8855_RG_GPIO_LED_MODE, val);
928 + /* Force clear blink pulse for per port LED */
929 + an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BLINK_DUR_CTRL, 0x1f);
931 + an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BLINK_DUR_CTRL, 0);
936 +static void an8855_port_isolation(struct an8855_switch_priv *priv)
940 + for (i = 0; i < AN8855_NUM_PORTS; i++) {
941 + /* Set port matrix mode */
943 + an8855_reg_write(priv, AN8855_PORTMATRIX_REG(i), 0x20);
945 + an8855_reg_write(priv, AN8855_PORTMATRIX_REG(i), 0x1f);
947 + /* Set port mode to user port */
948 + an8855_reg_write(priv, AN8855_PVC(i),
949 + (0x8100 << AN8855_STAG_VPID_S) |
950 + (VLAN_ATTR_USER << AN8855_VLAN_ATTR_S));
954 +static void an8855_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
956 + struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv;
957 + u32 pmcr = AN8855_FORCE_MODE_LNK;
960 + pmcr = AN8855_FORCE_MODE;
962 + an8855_reg_write(priv, AN8855_PMCR_REG(5), pmcr);
965 +static int an8855_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
967 + struct an8855_switch_priv *priv = bus->priv;
970 + return mtk_mii_read(priv->epriv.eth, addr, reg);
972 + return mtk_mmd_ind_read(priv->epriv.eth, addr, devad, reg);
975 +static int an8855_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
978 + struct an8855_switch_priv *priv = bus->priv;
981 + return mtk_mii_write(priv->epriv.eth, addr, reg, val);
983 + return mtk_mmd_ind_write(priv->epriv.eth, addr, devad, reg, val);
986 +static int an8855_mdio_register(struct an8855_switch_priv *priv)
988 + struct mii_dev *mdio_bus = mdio_alloc();
994 + mdio_bus->read = an8855_mdio_read;
995 + mdio_bus->write = an8855_mdio_write;
996 + snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
998 + mdio_bus->priv = priv;
1000 + ret = mdio_register(mdio_bus);
1002 + mdio_free(mdio_bus);
1006 + priv->mdio_bus = mdio_bus;
1011 +static int an8855_setup(struct mtk_eth_switch_priv *swpriv)
1013 + struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv;
1014 + u16 phy_addr, phy_val;
1015 + u32 i, id, val = 0;
1018 + priv->phy_base = 1;
1020 + /* Turn off PHYs */
1021 + for (i = 0; i < AN8855_NUM_PHYS; i++) {
1022 + phy_addr = AN8855_PHY_ADDR(priv->phy_base, i);
1023 + phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
1024 + phy_val |= BMCR_PDOWN;
1025 + mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
1028 + /* Force MAC link down before reset */
1029 + an8855_reg_write(priv, AN8855_PMCR_REG(5), AN8855_FORCE_MODE_LNK);
1031 + /* Switch soft reset */
1032 + an8855_reg_write(priv, AN8855_SYS_CTRL_REG, AN8855_SW_SYS_RST);
1035 + an8855_reg_read(priv, AN8855_PKG_SEL, &val);
1036 + if ((val & 0x7) == PAG_SEL_AN8855H) {
1037 + /* Release power down */
1038 + an8855_reg_write(priv, RG_GPHY_AFE_PWD, 0x0);
1040 + /* Invert for LED activity change */
1041 + an8855_reg_read(priv, AN8855_RG_GPIO_L_INV, &val);
1042 + for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
1043 + if ((led_cfg[id].pol == LED_HIGH) &&
1044 + (led_cfg[id].en == 1))
1047 + an8855_reg_write(priv, AN8855_RG_GPIO_L_INV, (val | 0x1));
1050 + an8855_reg_write(priv, AN8855_RG_GDMP_RAM, 0x846);
1051 + an8855_reg_write(priv, AN8855_RG_GDMP_RAM + 4, 0x4a);
1054 + an8855_reg_read(priv, AN8855_RG_CLK_CPU_ICG, &val);
1055 + an8855_reg_write(priv, AN8855_RG_CLK_CPU_ICG,
1056 + val | AN8855_MCU_ENABLE);
1059 + /* Disable MCU watchdog */
1060 + an8855_reg_read(priv, AN8855_RG_TIMER_CTL, &val);
1061 + an8855_reg_write(priv, AN8855_RG_TIMER_CTL,
1062 + (val & (~AN8855_WDOG_ENABLE)));
1064 + /* LED settings for T830 reference board */
1065 + ret = an8855_led_init(priv);
1067 + printf("an8855: an8855_led_init failed with %d\n", ret);
1072 + switch (priv->epriv.phy_interface) {
1073 + case PHY_INTERFACE_MODE_2500BASEX:
1074 + an8855_port_sgmii_init(priv, 5);
1081 + an8855_reg_read(priv, AN8855_CKGCR, &val);
1083 + an8855_reg_write(priv, AN8855_CKGCR, val);
1085 + /* Enable port isolation to block inter-port communication */
1086 + an8855_port_isolation(priv);
1088 + /* Turn on PHYs */
1089 + for (i = 0; i < AN8855_NUM_PHYS; i++) {
1090 + phy_addr = AN8855_PHY_ADDR(priv->phy_base, i);
1091 + phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
1092 + phy_val &= ~BMCR_PDOWN;
1093 + mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
1096 + return an8855_mdio_register(priv);
1099 +static int an8855_cleanup(struct mtk_eth_switch_priv *swpriv)
1101 + struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv;
1103 + mdio_unregister(priv->mdio_bus);
1108 +static int an8855_detect(struct mtk_eth_priv *priv)
1113 + ret = __an8855_reg_read(priv, 1, 0x10005000, &val);
1117 + if (val == 0x8855)
1123 +MTK_ETH_SWITCH(an8855) = {
1125 + .desc = "Airoha AN8855",
1126 + .priv_size = sizeof(struct an8855_switch_priv),
1127 + .reset_wait_time = 100,
1129 + .detect = an8855_detect,
1130 + .setup = an8855_setup,
1131 + .cleanup = an8855_cleanup,
1132 + .mac_control = an8855_mac_control,