]> git.ipfire.org Git - thirdparty/openwrt.git/blob
8e4f4391b10c594cca82cbbb222dea5724a63d2b
[thirdparty/openwrt.git] /
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
5 switch
6
7 Airoha AN8855 is a 5-port gigabit switch with a 2.5G HSGMII CPU port
8
9 Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
10 ---
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
16
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
21 default y
22
23 +config MTK_ETH_SWITCH_AN8855
24 + bool "Support for Airoha AN8855 ethernet switch"
25 + default y if TARGET_MT7981 || TARGET_MT7987
26 +
27 endif # MEDIATEK_ETH
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
35 --- /dev/null
36 +++ b/drivers/net/mtk_eth/an8855.c
37 @@ -0,0 +1,1096 @@
38 +// SPDX-License-Identifier: GPL-2.0
39 +/*
40 + * Copyright (C) 2025 MediaTek Inc.
41 + *
42 + * Author: Neal Yen <neal.yen@mediatek.com>
43 + * Author: Weijie Gao <weijie.gao@mediatek.com>
44 + */
45 +
46 +#include <phy.h>
47 +#include <miiphy.h>
48 +#include <linux/bitops.h>
49 +#include <linux/delay.h>
50 +#include <linux/mdio.h>
51 +#include <linux/mii.h>
52 +#include "mtk_eth.h"
53 +
54 +/* AN8855 Register Definitions */
55 +#define AN8855_SYS_CTRL_REG 0x100050c0
56 +#define AN8855_SW_SYS_RST BIT(31)
57 +
58 +#define AN8855_PMCR_REG(p) (0x10210000 + (p) * 0x200)
59 +#define AN8855_FORCE_MODE_LNK BIT(31)
60 +#define AN8855_FORCE_MODE 0xb31593f0
61 +
62 +#define AN8855_PORT_CTRL_BASE (0x10208000)
63 +#define AN8855_PORT_CTRL_REG(p, r) (AN8855_PORT_CTRL_BASE + (p) * 0x200 + (r))
64 +
65 +#define AN8855_PORTMATRIX_REG(p) AN8855_PORT_CTRL_REG(p, 0x44)
66 +
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
72 +
73 +#define VLAN_ATTR_USER 0
74 +
75 +#define AN8855_INT_MASK 0x100050F0
76 +#define AN8855_INT_SYS_BIT BIT(15)
77 +
78 +#define AN8855_RG_CLK_CPU_ICG 0x10005034
79 +#define AN8855_MCU_ENABLE BIT(3)
80 +
81 +#define AN8855_RG_TIMER_CTL 0x1000a100
82 +#define AN8855_WDOG_ENABLE BIT(25)
83 +
84 +#define AN8855_CKGCR 0x10213e1c
85 +
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)
96 +
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)
101 +
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)
105 +
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)
112 +
113 +#define AN8855_XFI_CSR_PCS_BASE 0x10225000
114 +#define AN8855_RG_USXGMII_AN_CONTROL_0 (AN8855_XFI_CSR_PCS_BASE + 0xbf8)
115 +
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)
120 +
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)
125 +
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)
129 +
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)
149 +
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)
161 +
162 +#define AN8855_ETHER_SYS_BASE 0x1028c800
163 +#define RG_GPHY_AFE_PWD (AN8855_ETHER_SYS_BASE + 0x40)
164 +
165 +#define AN8855_PKG_SEL 0x10000094
166 +#define PAG_SEL_AN8855H 0x2
167 +
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))
174 +
175 +#define PHY_PMA_CTRL (0x340)
176 +
177 +#define PHY_DEV1F 0x1f
178 +
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)
183 +
184 +/* LED ON Event */
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)
192 +
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)
203 +
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)
210 +
211 +#define PHY_LED_ON_DUR (0x22)
212 +#define LED_ON_DUR_MASK (0xffff)
213 +
214 +#define PHY_LED_BLK_DUR (0x23)
215 +#define LED_BLK_DUR_MASK (0xffff)
216 +
217 +#define PHY_LED_BLINK_DUR_CTRL (0x720)
218 +
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)
223 +
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)
230 +
231 +#define LED_FREQ AIR_LED_BLK_DUR_64M
232 +
233 +#define AN8855_NUM_PHYS 5
234 +#define AN8855_NUM_PORTS 6
235 +#define AN8855_PHY_ADDR(base, addr) (((base) + (addr)) & 0x1f)
236 +
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))
243 +
244 +/* AN8855 LED */
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
253 +};
254 +
255 +enum an8855_led_polarity {
256 + LED_LOW,
257 + LED_HIGH,
258 +};
259 +
260 +enum an8855_led_mode {
261 + AN8855_LED_MODE_DISABLE,
262 + AN8855_LED_MODE_USER_DEFINE,
263 + AN8855_LED_MODE_LAST
264 +};
265 +
266 +enum phy_led_idx {
267 + P0_LED0,
268 + P0_LED1,
269 + P0_LED2,
270 + P0_LED3,
271 + P1_LED0,
272 + P1_LED1,
273 + P1_LED2,
274 + P1_LED3,
275 + P2_LED0,
276 + P2_LED1,
277 + P2_LED2,
278 + P2_LED3,
279 + P3_LED0,
280 + P3_LED1,
281 + P3_LED2,
282 + P3_LED3,
283 + P4_LED0,
284 + P4_LED1,
285 + P4_LED2,
286 + P4_LED3,
287 + PHY_LED_MAX
288 +};
289 +
290 +struct an8855_led_cfg {
291 + u16 en;
292 + u8 phy_led_idx;
293 + u16 pol;
294 + u16 on_cfg;
295 + u16 blk_cfg;
296 + u8 led_freq;
297 +};
298 +
299 +struct an8855_switch_priv {
300 + struct mtk_eth_switch_priv epriv;
301 + struct mii_dev *mdio_bus;
302 + u32 phy_base;
303 +};
304 +
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 + *************************************************************************
310 + */
311 + /* GPIO0 */
312 + {1, P4_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
313 + /* GPIO1 */
314 + {1, P4_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
315 + /* GPIO2 */
316 + {1, P0_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
317 + /* GPIO3 */
318 + {1, P0_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
319 + /* GPIO4 */
320 + {1, P1_LED0, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
321 + /* GPIO5 */
322 + {1, P1_LED1, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
323 + /* GPIO6 */
324 + {0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
325 + /* GPIO7 */
326 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
327 + /* GPIO8 */
328 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
329 + /* GPIO9 */
330 + {1, P2_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
331 + /* GPIO10 */
332 + {1, P2_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
333 + /* GPIO11 */
334 + {1, P3_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
335 + /* GPIO12 */
336 + {1, P3_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
337 + /* GPIO13 */
338 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
339 + /* GPIO14 */
340 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
341 + /* GPIO15 */
342 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
343 + /* GPIO16 */
344 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
345 + /* GPIO17 */
346 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
347 + /* GPIO18 */
348 + {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
349 + /* GPIO19 */
350 + {0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
351 + /* GPIO20 */
352 + {0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ},
353 +};
354 +
355 +static int __an8855_reg_read(struct mtk_eth_priv *priv, u8 phy_base, u32 reg, u32 *data)
356 +{
357 + int ret, low_word, high_word;
358 +
359 + ret = mtk_mii_write(priv, phy_base, 0x1f, 0x4);
360 + if (ret)
361 + return ret;
362 +
363 + ret = mtk_mii_write(priv, phy_base, 0x10, 0);
364 + if (ret)
365 + return ret;
366 +
367 + ret = mtk_mii_write(priv, phy_base, 0x15, ((reg >> 16) & 0xFFFF));
368 + if (ret)
369 + return ret;
370 +
371 + ret = mtk_mii_write(priv, phy_base, 0x16, (reg & 0xFFFF));
372 + if (ret)
373 + return ret;
374 +
375 + low_word = mtk_mii_read(priv, phy_base, 0x18);
376 + if (low_word < 0)
377 + return low_word;
378 +
379 + high_word = mtk_mii_read(priv, phy_base, 0x17);
380 + if (high_word < 0)
381 + return high_word;
382 +
383 + ret = mtk_mii_write(priv, phy_base, 0x1f, 0);
384 + if (ret)
385 + return ret;
386 +
387 + ret = mtk_mii_write(priv, phy_base, 0x10, 0);
388 + if (ret)
389 + return ret;
390 +
391 + if (data)
392 + *data = ((u32)high_word << 16) | (low_word & 0xffff);
393 +
394 + return 0;
395 +}
396 +
397 +static int an8855_reg_read(struct an8855_switch_priv *priv, u32 reg, u32 *data)
398 +{
399 + return __an8855_reg_read(priv->epriv.eth, priv->phy_base, reg, data);
400 +}
401 +
402 +static int an8855_reg_write(struct an8855_switch_priv *priv, u32 reg, u32 data)
403 +{
404 + int ret;
405 +
406 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x1f, 0x4);
407 + if (ret)
408 + return ret;
409 +
410 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x10, 0);
411 + if (ret)
412 + return ret;
413 +
414 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x11,
415 + ((reg >> 16) & 0xFFFF));
416 + if (ret)
417 + return ret;
418 +
419 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x12,
420 + (reg & 0xFFFF));
421 + if (ret)
422 + return ret;
423 +
424 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x13,
425 + ((data >> 16) & 0xFFFF));
426 + if (ret)
427 + return ret;
428 +
429 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x14,
430 + (data & 0xFFFF));
431 + if (ret)
432 + return ret;
433 +
434 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x1f, 0);
435 + if (ret)
436 + return ret;
437 +
438 + ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x10, 0);
439 + if (ret)
440 + return ret;
441 +
442 + return 0;
443 +}
444 +
445 +static int an8855_phy_cl45_read(struct an8855_switch_priv *priv, int port,
446 + int devad, int regnum, u16 *data)
447 +{
448 + u16 phy_addr = AN8855_PHY_ADDR(priv->phy_base, port);
449 +
450 + *data = mtk_mmd_ind_read(priv->epriv.eth, phy_addr, devad, regnum);
451 +
452 + return 0;
453 +}
454 +
455 +static int an8855_phy_cl45_write(struct an8855_switch_priv *priv, int port,
456 + int devad, int regnum, u16 data)
457 +{
458 + u16 phy_addr = AN8855_PHY_ADDR(priv->phy_base, port);
459 +
460 + mtk_mmd_ind_write(priv->epriv.eth, phy_addr, devad, regnum, data);
461 +
462 + return 0;
463 +}
464 +
465 +static int an8855_port_sgmii_init(struct an8855_switch_priv *priv, u32 port)
466 +{
467 + u32 val = 0;
468 +
469 + if (port != 5) {
470 + printf("an8855: port %d is not a SGMII port\n", port);
471 + return -EINVAL;
472 + }
473 +
474 + /* PLL */
475 + an8855_reg_read(priv, AN8855_QP_DIG_MODE_CTRL_1, &val);
476 + val &= ~(0x3 << 2);
477 + val |= (0x1 << 2);
478 + an8855_reg_write(priv, AN8855_QP_DIG_MODE_CTRL_1, val);
479 +
480 + /* PLL - LPF */
481 + an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
482 + val &= ~(0x3 << 0);
483 + val |= (0x1 << 0);
484 + val &= ~(0x7 << 2);
485 + val |= (0x5 << 2);
486 + val &= ~GENMASK(7, 6);
487 + val &= ~(0x7 << 8);
488 + val |= (0x3 << 8);
489 + val |= BIT(29);
490 + val &= ~GENMASK(13, 12);
491 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
492 +
493 + /* PLL - ICO */
494 + an8855_reg_read(priv, AN8855_PLL_CTRL_4, &val);
495 + val |= BIT(2);
496 + an8855_reg_write(priv, AN8855_PLL_CTRL_4, val);
497 +
498 + an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
499 + val &= ~BIT(14);
500 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
501 +
502 + /* PLL - CHP */
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);
507 +
508 + /* PLL - PFD */
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);
514 + val &= ~BIT(26);
515 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
516 +
517 + /* PLL - POSTDIV */
518 + an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
519 + val |= BIT(22);
520 + val &= ~BIT(27);
521 + val &= ~BIT(28);
522 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
523 +
524 + /* PLL - SDM */
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);
528 +
529 + an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val);
530 + val &= ~BIT(30);
531 + an8855_reg_write(priv, AN8855_PLL_CTRL_2, val);
532 +
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);
537 +
538 + an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_FLT_2, 0x7a000000);
539 + an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_PCW_1, 0x7a000000);
540 +
541 + an8855_reg_read(priv, AN8855_SS_LCPLL_TDC_FLT_5, &val);
542 + val &= ~BIT(24);
543 + an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_FLT_5, val);
544 +
545 + an8855_reg_read(priv, AN8855_PLL_CK_CTRL_0, &val);
546 + val &= ~BIT(8);
547 + an8855_reg_write(priv, AN8855_PLL_CK_CTRL_0, val);
548 +
549 + /* PLL - SS */
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);
553 +
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);
557 +
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);
561 +
562 + /* PLL - TDC */
563 + an8855_reg_read(priv, AN8855_PLL_CK_CTRL_0, &val);
564 + val &= ~BIT(9);
565 + an8855_reg_write(priv, AN8855_PLL_CK_CTRL_0, val);
566 +
567 + an8855_reg_read(priv, AN8855_RG_QP_PLL_SDM_ORD, &val);
568 + val |= BIT(3);
569 + val |= BIT(4);
570 + an8855_reg_write(priv, AN8855_RG_QP_PLL_SDM_ORD, val);
571 +
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);
576 +
577 + /* TCL Disable (only for Co-SIM) */
578 + an8855_reg_read(priv, AN8855_PON_RXFEDIG_CTRL_0, &val);
579 + val &= ~BIT(12);
580 + an8855_reg_write(priv, AN8855_PON_RXFEDIG_CTRL_0, val);
581 +
582 + /* TX Init */
583 + an8855_reg_read(priv, AN8855_RG_QP_TX_MODE_16B_EN, &val);
584 + val &= ~BIT(0);
585 + val &= ~(0xffff << 16);
586 + val |= (0x4 << 16);
587 + an8855_reg_write(priv, AN8855_RG_QP_TX_MODE_16B_EN, val);
588 +
589 + /* RX Control */
590 + an8855_reg_read(priv, AN8855_RG_QP_RXAFE_RESERVE, &val);
591 + val |= BIT(11);
592 + an8855_reg_write(priv, AN8855_RG_QP_RXAFE_RESERVE, val);
593 +
594 + an8855_reg_read(priv, AN8855_RG_QP_CDR_LPF_MJV_LIM, &val);
595 + val &= ~(0x3 << 4);
596 + val |= (0x1 << 4);
597 + an8855_reg_write(priv, AN8855_RG_QP_CDR_LPF_MJV_LIM, val);
598 +
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);
605 +
606 + an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, &val);
607 + val &= ~(0x1f << 8);
608 + val |= (0xf << 8);
609 + an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, val);
610 +
611 + an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, &val);
612 + val &= ~(0x3f << 0);
613 + val |= (0x19 << 0);
614 + val &= ~BIT(6);
615 + an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
616 +
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);
622 + val &= ~BIT(13);
623 + an8855_reg_write(priv, AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF, val);
624 +
625 + an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, &val);
626 + val &= ~BIT(30);
627 + an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, val);
628 +
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);
633 +
634 + an8855_reg_read(priv, AN8855_PLL_CTRL_0, &val);
635 + val |= BIT(0);
636 + an8855_reg_write(priv, AN8855_PLL_CTRL_0, val);
637 +
638 + an8855_reg_read(priv, AN8855_RX_CTRL_26, &val);
639 + val &= ~BIT(23);
640 + val |= BIT(26);
641 + an8855_reg_write(priv, AN8855_RX_CTRL_26, val);
642 +
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);
648 +
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);
653 +
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);
658 +
659 + an8855_reg_read(priv, AN8855_PON_RXFEDIG_CTRL_9, &val);
660 + val &= ~(0x7 << 0);
661 + val |= (0x1 << 0);
662 + an8855_reg_write(priv, AN8855_PON_RXFEDIG_CTRL_9, val);
663 +
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);
670 +
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);
676 +
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);
681 +
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);
686 +
687 + /* PCS Init */
688 + an8855_reg_read(priv, AN8855_RG_HSGMII_PCS_CTROL_1, &val);
689 + val &= ~BIT(30);
690 + an8855_reg_write(priv, AN8855_RG_HSGMII_PCS_CTROL_1, val);
691 +
692 + /* Rate Adaption */
693 + an8855_reg_read(priv, AN8855_RATE_ADP_P0_CTRL_0, &val);
694 + val &= ~BIT(31);
695 + an8855_reg_write(priv, AN8855_RATE_ADP_P0_CTRL_0, val);
696 +
697 + an8855_reg_read(priv, AN8855_RG_RATE_ADAPT_CTRL_0, &val);
698 + val |= BIT(0);
699 + val |= BIT(4);
700 + val |= GENMASK(27, 26);
701 + an8855_reg_write(priv, AN8855_RG_RATE_ADAPT_CTRL_0, val);
702 +
703 + /* Disable AN */
704 + an8855_reg_read(priv, AN8855_SGMII_REG_AN0, &val);
705 + val &= ~BIT(12);
706 + an8855_reg_write(priv, AN8855_SGMII_REG_AN0, val);
707 +
708 + /* Force Speed */
709 + an8855_reg_read(priv, AN8855_SGMII_STS_CTRL_0, &val);
710 + val |= BIT(2);
711 + val |= GENMASK(5, 4);
712 + an8855_reg_write(priv, AN8855_SGMII_STS_CTRL_0, val);
713 +
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);
717 +
718 + return 0;
719 +}
720 +
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)
724 +{
725 + u32 cl45_data;
726 +
727 + if (pol == LED_HIGH)
728 + on_evt |= LED_ON_POL;
729 + else
730 + on_evt &= ~LED_ON_POL;
731 +
732 + /* LED on event */
733 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
734 + PHY_SINGLE_LED_ON_CTRL(entity % 4),
735 + on_evt | LED_ON_EN);
736 +
737 + /* LED blink event */
738 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
739 + PHY_SINGLE_LED_BLK_CTRL(entity % 4),
740 + blk_evt);
741 +
742 + /* LED freq */
743 + switch (led_freq) {
744 + case AIR_LED_BLK_DUR_32M:
745 + cl45_data = 0x30e;
746 + break;
747 +
748 + case AIR_LED_BLK_DUR_64M:
749 + cl45_data = 0x61a;
750 + break;
751 +
752 + case AIR_LED_BLK_DUR_128M:
753 + cl45_data = 0xc35;
754 + break;
755 +
756 + case AIR_LED_BLK_DUR_256M:
757 + cl45_data = 0x186a;
758 + break;
759 +
760 + case AIR_LED_BLK_DUR_512M:
761 + cl45_data = 0x30d4;
762 + break;
763 +
764 + case AIR_LED_BLK_DUR_1024M:
765 + cl45_data = 0x61a8;
766 + break;
767 +
768 + default:
769 + cl45_data = 0;
770 + break;
771 + }
772 +
773 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
774 + PHY_SINGLE_LED_BLK_DUR(entity % 4),
775 + cl45_data);
776 +
777 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
778 + PHY_SINGLE_LED_ON_DUR(entity % 4),
779 + (cl45_data >> 1));
780 +
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);
786 +}
787 +
788 +static int an8855_led_set_mode(struct an8855_switch_priv *priv, u8 mode)
789 +{
790 + u16 cl45_data;
791 +
792 + an8855_phy_cl45_read(priv, 0, 0x1f, PHY_LED_BCR, &cl45_data);
793 +
794 + switch (mode) {
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;
799 + break;
800 +
801 + case AN8855_LED_MODE_USER_DEFINE:
802 + cl45_data |= LED_BCR_EXT_CTRL;
803 + cl45_data |= LED_BCR_CLK_EN;
804 + break;
805 +
806 + default:
807 + printf("an8855: LED mode%d is not supported!\n", mode);
808 + return -EINVAL;
809 + }
810 +
811 + an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BCR, cl45_data);
812 +
813 + return 0;
814 +}
815 +
816 +static int an8855_led_set_state(struct an8855_switch_priv *priv, u8 entity,
817 + u8 state)
818 +{
819 + u16 cl45_data = 0;
820 +
821 + /* Change to per port contorl */
822 + an8855_phy_cl45_read(priv, (entity / 4), 0x1e, PHY_LED_CTRL_SELECT,
823 + &cl45_data);
824 +
825 + if (state == 1)
826 + cl45_data |= (1 << (entity % 4));
827 + else
828 + cl45_data &= ~(1 << (entity % 4));
829 +
830 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e, PHY_LED_CTRL_SELECT,
831 + cl45_data);
832 +
833 + /* LED enable setting */
834 + an8855_phy_cl45_read(priv, (entity / 4), 0x1e,
835 + PHY_SINGLE_LED_ON_CTRL(entity % 4), &cl45_data);
836 +
837 + if (state == 1)
838 + cl45_data |= LED_ON_EN;
839 + else
840 + cl45_data &= ~LED_ON_EN;
841 +
842 + an8855_phy_cl45_write(priv, (entity / 4), 0x1e,
843 + PHY_SINGLE_LED_ON_CTRL(entity % 4), cl45_data);
844 +
845 + return 0;
846 +}
847 +
848 +static int an8855_led_init(struct an8855_switch_priv *priv)
849 +{
850 + u32 val, id, tmp_id = 0;
851 + int ret;
852 +
853 + ret = an8855_led_set_mode(priv, AN8855_LED_MODE_USER_DEFINE);
854 + if (ret) {
855 + printf("an8855: led_set_mode failed with %d!\n", ret);
856 + return ret;
857 + }
858 +
859 + for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
860 + ret = an8855_led_set_state(priv, led_cfg[id].phy_led_idx,
861 + led_cfg[id].en);
862 + if (ret != 0) {
863 + printf("an8855: led_set_state failed with %d!\n", ret);
864 + return ret;
865 + }
866 +
867 + if (led_cfg[id].en == 1) {
868 + an8855_led_set_usr_def(priv,
869 + led_cfg[id].phy_led_idx,
870 + led_cfg[id].pol,
871 + led_cfg[id].on_cfg,
872 + led_cfg[id].blk_cfg,
873 + led_cfg[id].led_freq);
874 + }
875 + }
876 +
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);
881 +
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);
885 + val &= ~(BIT(0));
886 + val &= ~(BIT(6));
887 + an8855_reg_write(priv, AN8855_RG_GPIO_DATA, val);
888 +
889 + an8855_reg_read(priv, AN8855_RG_GPIO_OE, &val);
890 + val |= 0x41;
891 + an8855_reg_write(priv, AN8855_RG_GPIO_OE, val);
892 +
893 + /* Mapping between GPIO & LED */
894 + val = 0;
895 + for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
896 + /* Skip GPIO6, due to GPIO6 does not support PORT LED */
897 + if (id == 6)
898 + continue;
899 +
900 + if (led_cfg[id].en == 1) {
901 + if (id < 7)
902 + val |= led_cfg[id].phy_led_idx << ((id % 4) * 8);
903 + else
904 + val |= led_cfg[id].phy_led_idx << (((id - 1) % 4) * 8);
905 + }
906 +
907 + if (id < 7)
908 + tmp_id = id;
909 + else
910 + tmp_id = id - 1;
911 +
912 + if ((tmp_id % 4) == 0x3) {
913 + an8855_reg_write(priv,
914 + AN8855_RG_GPIO_LED_SEL(tmp_id / 4),
915 + val);
916 + val = 0;
917 + }
918 + }
919 +
920 + /* Turn on LAN LED mode */
921 + val = 0;
922 + for (id = 0; id < ARRAY_SIZE(led_cfg); id++) {
923 + if (led_cfg[id].en == 1)
924 + val |= 0x1 << id;
925 + }
926 + an8855_reg_write(priv, AN8855_RG_GPIO_LED_MODE, val);
927 +
928 + /* Force clear blink pulse for per port LED */
929 + an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BLINK_DUR_CTRL, 0x1f);
930 + udelay(1000);
931 + an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BLINK_DUR_CTRL, 0);
932 +
933 + return 0;
934 +}
935 +
936 +static void an8855_port_isolation(struct an8855_switch_priv *priv)
937 +{
938 + u32 i;
939 +
940 + for (i = 0; i < AN8855_NUM_PORTS; i++) {
941 + /* Set port matrix mode */
942 + if (i != 5)
943 + an8855_reg_write(priv, AN8855_PORTMATRIX_REG(i), 0x20);
944 + else
945 + an8855_reg_write(priv, AN8855_PORTMATRIX_REG(i), 0x1f);
946 +
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));
951 + }
952 +}
953 +
954 +static void an8855_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
955 +{
956 + struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv;
957 + u32 pmcr = AN8855_FORCE_MODE_LNK;
958 +
959 + if (enable)
960 + pmcr = AN8855_FORCE_MODE;
961 +
962 + an8855_reg_write(priv, AN8855_PMCR_REG(5), pmcr);
963 +}
964 +
965 +static int an8855_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
966 +{
967 + struct an8855_switch_priv *priv = bus->priv;
968 +
969 + if (devad < 0)
970 + return mtk_mii_read(priv->epriv.eth, addr, reg);
971 +
972 + return mtk_mmd_ind_read(priv->epriv.eth, addr, devad, reg);
973 +}
974 +
975 +static int an8855_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
976 + u16 val)
977 +{
978 + struct an8855_switch_priv *priv = bus->priv;
979 +
980 + if (devad < 0)
981 + return mtk_mii_write(priv->epriv.eth, addr, reg, val);
982 +
983 + return mtk_mmd_ind_write(priv->epriv.eth, addr, devad, reg, val);
984 +}
985 +
986 +static int an8855_mdio_register(struct an8855_switch_priv *priv)
987 +{
988 + struct mii_dev *mdio_bus = mdio_alloc();
989 + int ret;
990 +
991 + if (!mdio_bus)
992 + return -ENOMEM;
993 +
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);
997 +
998 + mdio_bus->priv = priv;
999 +
1000 + ret = mdio_register(mdio_bus);
1001 + if (ret) {
1002 + mdio_free(mdio_bus);
1003 + return ret;
1004 + }
1005 +
1006 + priv->mdio_bus = mdio_bus;
1007 +
1008 + return 0;
1009 +}
1010 +
1011 +static int an8855_setup(struct mtk_eth_switch_priv *swpriv)
1012 +{
1013 + struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv;
1014 + u16 phy_addr, phy_val;
1015 + u32 i, id, val = 0;
1016 + int ret;
1017 +
1018 + priv->phy_base = 1;
1019 +
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);
1026 + }
1027 +
1028 + /* Force MAC link down before reset */
1029 + an8855_reg_write(priv, AN8855_PMCR_REG(5), AN8855_FORCE_MODE_LNK);
1030 +
1031 + /* Switch soft reset */
1032 + an8855_reg_write(priv, AN8855_SYS_CTRL_REG, AN8855_SW_SYS_RST);
1033 + udelay(100000);
1034 +
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);
1039 +
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))
1045 + val |= 0x1 << id;
1046 + }
1047 + an8855_reg_write(priv, AN8855_RG_GPIO_L_INV, (val | 0x1));
1048 +
1049 + /* MCU NOP CMD */
1050 + an8855_reg_write(priv, AN8855_RG_GDMP_RAM, 0x846);
1051 + an8855_reg_write(priv, AN8855_RG_GDMP_RAM + 4, 0x4a);
1052 +
1053 + /* Enable MCU */
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);
1057 + udelay(1000);
1058 +
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)));
1063 +
1064 + /* LED settings for T830 reference board */
1065 + ret = an8855_led_init(priv);
1066 + if (ret < 0) {
1067 + printf("an8855: an8855_led_init failed with %d\n", ret);
1068 + return ret;
1069 + }
1070 + }
1071 +
1072 + switch (priv->epriv.phy_interface) {
1073 + case PHY_INTERFACE_MODE_2500BASEX:
1074 + an8855_port_sgmii_init(priv, 5);
1075 + break;
1076 +
1077 + default:
1078 + break;
1079 + }
1080 +
1081 + an8855_reg_read(priv, AN8855_CKGCR, &val);
1082 + val &= ~(0x3);
1083 + an8855_reg_write(priv, AN8855_CKGCR, val);
1084 +
1085 + /* Enable port isolation to block inter-port communication */
1086 + an8855_port_isolation(priv);
1087 +
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);
1094 + }
1095 +
1096 + return an8855_mdio_register(priv);
1097 +}
1098 +
1099 +static int an8855_cleanup(struct mtk_eth_switch_priv *swpriv)
1100 +{
1101 + struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv;
1102 +
1103 + mdio_unregister(priv->mdio_bus);
1104 +
1105 + return 0;
1106 +}
1107 +
1108 +static int an8855_detect(struct mtk_eth_priv *priv)
1109 +{
1110 + int ret;
1111 + u32 val;
1112 +
1113 + ret = __an8855_reg_read(priv, 1, 0x10005000, &val);
1114 + if (ret)
1115 + return ret;
1116 +
1117 + if (val == 0x8855)
1118 + return 0;
1119 +
1120 + return -ENODEV;
1121 +}
1122 +
1123 +MTK_ETH_SWITCH(an8855) = {
1124 + .name = "an8855",
1125 + .desc = "Airoha AN8855",
1126 + .priv_size = sizeof(struct an8855_switch_priv),
1127 + .reset_wait_time = 100,
1128 +
1129 + .detect = an8855_detect,
1130 + .setup = an8855_setup,
1131 + .cleanup = an8855_cleanup,
1132 + .mac_control = an8855_mac_control,
1133 +};