]>
Commit | Line | Data |
---|---|---|
c5620aee HV |
1 | // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
2 | /* | |
3 | * Copyright (c) 2019 Microsemi Corporation | |
4 | */ | |
5 | ||
6 | #include <common.h> | |
7 | #include <config.h> | |
8 | #include <dm.h> | |
336d4615 | 9 | #include <malloc.h> |
c5620aee HV |
10 | #include <dm/of_access.h> |
11 | #include <dm/of_addr.h> | |
12 | #include <fdt_support.h> | |
13 | #include <linux/io.h> | |
14 | #include <linux/ioport.h> | |
15 | #include <miiphy.h> | |
16 | #include <net.h> | |
17 | #include <wait_bit.h> | |
18 | ||
c5620aee HV |
19 | #include "mscc_xfer.h" |
20 | #include "mscc_mac_table.h" | |
61243678 | 21 | #include "mscc_miim.h" |
7e323f17 | 22 | |
c5620aee HV |
23 | #define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x)) |
24 | #define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) | |
25 | #define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) | |
26 | #define ANA_PORT_CPU_FWD_CFG(x) (0x50 + 0x80 * (x)) | |
27 | #define ANA_PORT_CPU_FWD_CFG_SRC_COPY_ENA BIT(1) | |
28 | #define ANA_PORT_PORT_CFG(x) (0x60 + 0x80 * (x)) | |
29 | #define ANA_PORT_PORT_CFG_RECV_ENA BIT(5) | |
30 | #define ANA_PGID(x) (0x1000 + 4 * (x)) | |
31 | ||
32 | #define SYS_FRM_AGING 0x8300 | |
33 | ||
34 | #define SYS_SYSTEM_RST_CFG 0x81b0 | |
35 | #define SYS_SYSTEM_RST_MEM_INIT BIT(0) | |
36 | #define SYS_SYSTEM_RST_MEM_ENA BIT(1) | |
37 | #define SYS_SYSTEM_RST_CORE_ENA BIT(2) | |
38 | #define SYS_PORT_MODE(x) (0x81bc + 0x4 * (x)) | |
39 | #define SYS_PORT_MODE_INCL_INJ_HDR BIT(0) | |
40 | #define SYS_SWITCH_PORT_MODE(x) (0x8294 + 0x4 * (x)) | |
41 | #define SYS_SWITCH_PORT_MODE_PORT_ENA BIT(3) | |
42 | #define SYS_EGR_NO_SHARING 0x8378 | |
43 | #define SYS_SCH_CPU 0x85a0 | |
44 | ||
45 | #define REW_PORT_CFG(x) (0x8 + 0x80 * (x)) | |
46 | #define REW_PORT_CFG_IFH_INSERT_ENA BIT(7) | |
47 | ||
48 | #define GCB_DEVCPU_RST_SOFT_CHIP_RST 0x90 | |
49 | #define GCB_DEVCPU_RST_SOFT_CHIP_RST_SOFT_PHY BIT(1) | |
50 | #define GCB_MISC_STAT 0x11c | |
51 | #define GCB_MISC_STAT_PHY_READY BIT(3) | |
52 | ||
53 | #define QS_XTR_MAP(x) (0x10 + 4 * (x)) | |
54 | #define QS_XTR_MAP_GRP BIT(4) | |
55 | #define QS_XTR_MAP_ENA BIT(0) | |
56 | ||
57 | #define HSIO_PLL5G_CFG_PLL5G_CFG2 0x8 | |
58 | ||
59 | #define HSIO_RCOMP_CFG_CFG0 0x20 | |
60 | #define HSIO_RCOMP_CFG_CFG0_MODE_SEL(x) ((x) << 8) | |
61 | #define HSIO_RCOMP_CFG_CFG0_RUN_CAL BIT(12) | |
62 | #define HSIO_RCOMP_STATUS 0x24 | |
63 | #define HSIO_RCOMP_STATUS_BUSY BIT(12) | |
64 | #define HSIO_RCOMP_STATUS_RCOMP_M GENMASK(3, 0) | |
65 | #define HSIO_SERDES6G_ANA_CFG_DES_CFG 0x64 | |
66 | #define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(x) ((x) << 1) | |
67 | #define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(x) ((x) << 5) | |
68 | #define HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(x) ((x) << 10) | |
69 | #define HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(x) ((x) << 13) | |
70 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG 0x68 | |
71 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(x) (x) | |
72 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(x) ((x) << 4) | |
73 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(x) ((x) << 7) | |
74 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(x) ((x) << 9) | |
75 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(x) ((x) << 14) | |
76 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG1 0x6c | |
77 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST BIT(0) | |
78 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC BIT(2) | |
79 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC BIT(3) | |
80 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE BIT(6) | |
81 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF BIT(7) | |
82 | #define HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(x) ((x) << 8) | |
83 | #define HSIO_SERDES6G_ANA_CFG_OB_CFG 0x70 | |
84 | #define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(x) ((x) << 4) | |
85 | #define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H BIT(8) | |
86 | #define HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(x) ((x) << 23) | |
87 | #define HSIO_SERDES6G_ANA_CFG_OB_CFG_POL BIT(29) | |
88 | #define HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE BIT(30) | |
89 | #define HSIO_SERDES6G_ANA_CFG_OB_CFG1 0x74 | |
90 | #define HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(x) (x) | |
91 | #define HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(x) ((x) << 6) | |
92 | #define HSIO_SERDES6G_ANA_CFG_COMMON_CFG 0x7c | |
93 | #define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(x) (x) | |
94 | #define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE BIT(18) | |
95 | #define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST BIT(31) | |
96 | #define HSIO_SERDES6G_ANA_CFG_PLL_CFG 0x80 | |
97 | #define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA BIT(7) | |
98 | #define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8) | |
99 | #define HSIO_SERDES6G_ANA_CFG_SER_CFG 0x84 | |
100 | #define HSIO_SERDES6G_DIG_CFG_MISC_CFG 0x88 | |
101 | #define HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST BIT(0) | |
102 | #define HSIO_MCB_SERDES6G_CFG 0xac | |
103 | #define HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT BIT(31) | |
104 | #define HSIO_MCB_SERDES6G_CFG_ADDR(x) (x) | |
105 | ||
106 | #define DEV_GMII_PORT_MODE_CLK 0x0 | |
107 | #define DEV_GMII_PORT_MODE_CLK_PHY_RST BIT(0) | |
108 | #define DEV_GMII_MAC_CFG_MAC_ENA 0xc | |
109 | #define DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA BIT(4) | |
110 | #define DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA BIT(0) | |
111 | ||
112 | #define DEV_PORT_MODE_CLK 0x4 | |
113 | #define DEV_PORT_MODE_CLK_PHY_RST BIT(2) | |
114 | #define DEV_PORT_MODE_CLK_LINK_SPEED_1000 1 | |
115 | #define DEV_MAC_CFG_MAC_ENA 0x10 | |
116 | #define DEV_MAC_CFG_MAC_ENA_RX_ENA BIT(4) | |
117 | #define DEV_MAC_CFG_MAC_ENA_TX_ENA BIT(0) | |
118 | #define DEV_MAC_CFG_MAC_IFG 0x24 | |
119 | #define DEV_MAC_CFG_MAC_IFG_TX_IFG(x) ((x) << 8) | |
120 | #define DEV_MAC_CFG_MAC_IFG_RX_IFG2(x) ((x) << 4) | |
121 | #define DEV_MAC_CFG_MAC_IFG_RX_IFG1(x) (x) | |
122 | #define DEV_PCS1G_CFG_PCS1G_CFG 0x40 | |
123 | #define DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA BIT(0) | |
124 | #define DEV_PCS1G_CFG_PCS1G_MODE 0x44 | |
125 | #define DEV_PCS1G_CFG_PCS1G_SD 0x48 | |
126 | #define DEV_PCS1G_CFG_PCS1G_ANEG 0x4c | |
127 | #define DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16) | |
128 | ||
129 | #define IFH_INJ_BYPASS BIT(31) | |
130 | #define IFH_TAG_TYPE_C 0 | |
131 | #define MAC_VID 1 | |
132 | #define CPU_PORT 26 | |
133 | #define INTERNAL_PORT_MSK 0xFFFFFF | |
134 | #define IFH_LEN 2 | |
135 | #define ETH_ALEN 6 | |
136 | #define PGID_BROADCAST 28 | |
137 | #define PGID_UNICAST 29 | |
138 | #define PGID_SRC 80 | |
139 | ||
7e323f17 HV |
140 | static const char * const regs_names[] = { |
141 | "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7", | |
142 | "port8", "port9", "port10", "port11", "port12", "port13", "port14", | |
143 | "port15", "port16", "port17", "port18", "port19", "port20", "port21", | |
144 | "port22", "port23", | |
145 | "sys", "ana", "rew", "gcb", "qs", "hsio", | |
146 | }; | |
147 | ||
148 | #define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1 | |
149 | #define MAX_PORT 24 | |
150 | ||
151 | enum luton_ctrl_regs { | |
152 | SYS = MAX_PORT, | |
c5620aee HV |
153 | ANA, |
154 | REW, | |
155 | GCB, | |
156 | QS, | |
7e323f17 | 157 | HSIO |
c5620aee HV |
158 | }; |
159 | ||
7e323f17 HV |
160 | #define MIN_INT_PORT 0 |
161 | #define PORT10 10 | |
162 | #define PORT11 11 | |
163 | #define MAX_INT_PORT 12 | |
164 | #define MIN_EXT_PORT MAX_INT_PORT | |
165 | #define MAX_EXT_PORT MAX_PORT | |
c5620aee | 166 | |
7e323f17 | 167 | #define LUTON_MIIM_BUS_COUNT 2 |
c5620aee | 168 | |
7e323f17 HV |
169 | struct luton_phy_port_t { |
170 | size_t phy_addr; | |
171 | struct mii_dev *bus; | |
172 | u8 serdes_index; | |
173 | u8 phy_mode; | |
c5620aee HV |
174 | }; |
175 | ||
7e323f17 HV |
176 | struct luton_private { |
177 | void __iomem *regs[REGS_NAMES_COUNT]; | |
178 | struct mii_dev *bus[LUTON_MIIM_BUS_COUNT]; | |
179 | struct luton_phy_port_t ports[MAX_PORT]; | |
c5620aee HV |
180 | }; |
181 | ||
c5620aee HV |
182 | static const unsigned long luton_regs_qs[] = { |
183 | [MSCC_QS_XTR_RD] = 0x18, | |
184 | [MSCC_QS_XTR_FLUSH] = 0x28, | |
185 | [MSCC_QS_XTR_DATA_PRESENT] = 0x2c, | |
186 | [MSCC_QS_INJ_WR] = 0x3c, | |
187 | [MSCC_QS_INJ_CTRL] = 0x44, | |
188 | }; | |
189 | ||
190 | static const unsigned long luton_regs_ana_table[] = { | |
191 | [MSCC_ANA_TABLES_MACHDATA] = 0x11b0, | |
192 | [MSCC_ANA_TABLES_MACLDATA] = 0x11b4, | |
193 | [MSCC_ANA_TABLES_MACACCESS] = 0x11b8, | |
194 | }; | |
195 | ||
7e323f17 HV |
196 | static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT]; |
197 | static int miim_count = -1; | |
c5620aee | 198 | |
c5620aee HV |
199 | static void luton_stop(struct udevice *dev) |
200 | { | |
201 | struct luton_private *priv = dev_get_priv(dev); | |
202 | ||
203 | /* | |
204 | * Switch core only reset affects VCORE-III bus and MIPS frequency | |
205 | * and thereby also the DDR SDRAM controller. The workaround is to | |
206 | * not to redirect any trafic to the CPU after the data transfer. | |
207 | */ | |
208 | writel(GENMASK(9, 2), priv->regs[SYS] + SYS_SCH_CPU); | |
209 | } | |
210 | ||
211 | static void luton_cpu_capture_setup(struct luton_private *priv) | |
212 | { | |
213 | int i; | |
214 | ||
215 | /* map the 8 CPU extraction queues to CPU port 26 */ | |
216 | writel(0x0, priv->regs[SYS] + SYS_SCH_CPU); | |
217 | ||
218 | for (i = 0; i <= 1; i++) { | |
219 | /* | |
220 | * One to one mapping from CPU Queue number to Group extraction | |
221 | * number | |
222 | */ | |
223 | writel(QS_XTR_MAP_ENA | (QS_XTR_MAP_GRP * i), | |
224 | priv->regs[QS] + QS_XTR_MAP(i)); | |
225 | ||
226 | /* Enable IFH insertion/parsing on CPU ports */ | |
227 | setbits_le32(priv->regs[REW] + REW_PORT_CFG(CPU_PORT + i), | |
228 | REW_PORT_CFG_IFH_INSERT_ENA); | |
229 | ||
230 | /* Enable IFH parsing on CPU port 0 and 1 */ | |
231 | setbits_le32(priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i), | |
232 | SYS_PORT_MODE_INCL_INJ_HDR); | |
233 | } | |
234 | ||
235 | /* Make VLAN aware for CPU traffic */ | |
236 | writel(ANA_PORT_VLAN_CFG_AWARE_ENA | | |
237 | ANA_PORT_VLAN_CFG_POP_CNT(1) | | |
238 | MAC_VID, | |
239 | priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT)); | |
240 | ||
241 | /* Disable learning (only RECV_ENA must be set) */ | |
242 | writel(ANA_PORT_PORT_CFG_RECV_ENA, | |
243 | priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT)); | |
244 | ||
245 | /* Enable switching to/from cpu port */ | |
246 | setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(CPU_PORT), | |
247 | SYS_SWITCH_PORT_MODE_PORT_ENA); | |
248 | ||
249 | setbits_le32(priv->regs[SYS] + SYS_EGR_NO_SHARING, BIT(CPU_PORT)); | |
250 | } | |
251 | ||
252 | static void luton_gmii_port_init(struct luton_private *priv, int port) | |
253 | { | |
254 | void __iomem *regs = priv->regs[port]; | |
255 | ||
256 | writel(0, regs + DEV_GMII_PORT_MODE_CLK); | |
257 | ||
258 | /* Enable MAC RX and TX */ | |
259 | writel(DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA | | |
260 | DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA, | |
261 | regs + DEV_GMII_MAC_CFG_MAC_ENA); | |
262 | ||
263 | /* Make VLAN aware for CPU traffic */ | |
264 | writel(ANA_PORT_VLAN_CFG_AWARE_ENA | | |
265 | ANA_PORT_VLAN_CFG_POP_CNT(1) | | |
266 | MAC_VID, | |
7e323f17 | 267 | priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); |
c5620aee HV |
268 | |
269 | /* Enable switching to/from port */ | |
7e323f17 | 270 | setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port), |
c5620aee HV |
271 | SYS_SWITCH_PORT_MODE_PORT_ENA); |
272 | } | |
273 | ||
274 | static void luton_port_init(struct luton_private *priv, int port) | |
275 | { | |
276 | void __iomem *regs = priv->regs[port]; | |
277 | ||
278 | writel(0, regs + DEV_PORT_MODE_CLK); | |
279 | ||
280 | /* Enable MAC RX and TX */ | |
281 | writel(DEV_MAC_CFG_MAC_ENA_RX_ENA | | |
282 | DEV_MAC_CFG_MAC_ENA_TX_ENA, | |
283 | regs + DEV_MAC_CFG_MAC_ENA); | |
284 | ||
285 | /* Make VLAN aware for CPU traffic */ | |
286 | writel(ANA_PORT_VLAN_CFG_AWARE_ENA | | |
287 | ANA_PORT_VLAN_CFG_POP_CNT(1) | | |
288 | MAC_VID, | |
7e323f17 | 289 | priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); |
c5620aee HV |
290 | |
291 | /* Enable switching to/from port */ | |
7e323f17 | 292 | setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port), |
c5620aee HV |
293 | SYS_SWITCH_PORT_MODE_PORT_ENA); |
294 | } | |
295 | ||
296 | static void luton_ext_port_init(struct luton_private *priv, int port) | |
297 | { | |
298 | void __iomem *regs = priv->regs[port]; | |
299 | ||
300 | /* Enable PCS */ | |
301 | writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA, | |
302 | regs + DEV_PCS1G_CFG_PCS1G_CFG); | |
303 | ||
304 | /* Disable Signal Detect */ | |
305 | writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD); | |
306 | ||
307 | /* Enable MAC RX and TX */ | |
308 | writel(DEV_MAC_CFG_MAC_ENA_RX_ENA | | |
309 | DEV_MAC_CFG_MAC_ENA_TX_ENA, | |
310 | regs + DEV_MAC_CFG_MAC_ENA); | |
311 | ||
312 | /* Clear sgmii_mode_ena */ | |
313 | writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE); | |
314 | ||
315 | /* | |
316 | * Clear sw_resolve_ena(bit 0) and set adv_ability to | |
317 | * something meaningful just in case | |
318 | */ | |
319 | writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20), | |
320 | regs + DEV_PCS1G_CFG_PCS1G_ANEG); | |
321 | ||
322 | /* Set MAC IFG Gaps */ | |
323 | writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(7) | | |
324 | DEV_MAC_CFG_MAC_IFG_RX_IFG1(1) | | |
325 | DEV_MAC_CFG_MAC_IFG_RX_IFG2(5), | |
326 | regs + DEV_MAC_CFG_MAC_IFG); | |
327 | ||
328 | /* Set link speed and release all resets */ | |
329 | writel(DEV_PORT_MODE_CLK_LINK_SPEED_1000, | |
330 | regs + DEV_PORT_MODE_CLK); | |
331 | ||
332 | /* Make VLAN aware for CPU traffic */ | |
333 | writel(ANA_PORT_VLAN_CFG_AWARE_ENA | | |
334 | ANA_PORT_VLAN_CFG_POP_CNT(1) | | |
335 | MAC_VID, | |
7e323f17 | 336 | priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); |
c5620aee HV |
337 | |
338 | /* Enable switching to/from port */ | |
7e323f17 | 339 | setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port), |
c5620aee HV |
340 | SYS_SWITCH_PORT_MODE_PORT_ENA); |
341 | } | |
342 | ||
7e323f17 | 343 | static void serdes6g_write(void __iomem *base, u32 addr) |
c5620aee HV |
344 | { |
345 | u32 data; | |
346 | ||
347 | writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT | | |
348 | HSIO_MCB_SERDES6G_CFG_ADDR(addr), | |
7e323f17 | 349 | base + HSIO_MCB_SERDES6G_CFG); |
c5620aee HV |
350 | |
351 | do { | |
7e323f17 | 352 | data = readl(base + HSIO_MCB_SERDES6G_CFG); |
c5620aee | 353 | } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT); |
c5620aee HV |
354 | } |
355 | ||
7e323f17 HV |
356 | static void serdes6g_setup(void __iomem *base, uint32_t addr, |
357 | phy_interface_t interface) | |
c5620aee HV |
358 | { |
359 | writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) | | |
360 | HSIO_RCOMP_CFG_CFG0_RUN_CAL, | |
7e323f17 | 361 | base + HSIO_RCOMP_CFG_CFG0); |
c5620aee | 362 | |
7e323f17 | 363 | while (readl(base + HSIO_RCOMP_STATUS) & |
c5620aee HV |
364 | HSIO_RCOMP_STATUS_BUSY) |
365 | ; | |
366 | ||
367 | writel(HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(0xb) | | |
368 | HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H | | |
369 | HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) | | |
370 | HSIO_SERDES6G_ANA_CFG_OB_CFG_POL | | |
371 | HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE, | |
7e323f17 | 372 | base + HSIO_SERDES6G_ANA_CFG_OB_CFG); |
c5620aee HV |
373 | writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) | |
374 | HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1), | |
7e323f17 | 375 | base + HSIO_SERDES6G_ANA_CFG_OB_CFG1); |
c5620aee HV |
376 | writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) | |
377 | HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) | | |
378 | HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) | | |
379 | HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) | | |
380 | HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4), | |
7e323f17 | 381 | base + HSIO_SERDES6G_ANA_CFG_IB_CFG); |
c5620aee HV |
382 | writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST | |
383 | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC | | |
384 | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC | | |
385 | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE | | |
386 | HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF | | |
387 | HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4), | |
7e323f17 | 388 | base + HSIO_SERDES6G_ANA_CFG_IB_CFG1); |
c5620aee HV |
389 | writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) | |
390 | HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) | | |
391 | HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) | | |
392 | HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6), | |
7e323f17 | 393 | base + HSIO_SERDES6G_ANA_CFG_DES_CFG); |
c5620aee HV |
394 | writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA | |
395 | HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78), | |
7e323f17 | 396 | base + HSIO_SERDES6G_ANA_CFG_PLL_CFG); |
c5620aee HV |
397 | writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) | |
398 | HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE, | |
7e323f17 | 399 | base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); |
c5620aee HV |
400 | /* |
401 | * There are 4 serdes6g, configure all except serdes6g0, therefore | |
402 | * the address is b1110 | |
403 | */ | |
7e323f17 | 404 | serdes6g_write(base, addr); |
c5620aee | 405 | |
7e323f17 | 406 | writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) | |
c5620aee | 407 | HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST, |
7e323f17 HV |
408 | base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); |
409 | serdes6g_write(base, addr); | |
c5620aee | 410 | |
7e323f17 | 411 | clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1, |
c5620aee HV |
412 | HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST); |
413 | writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST, | |
7e323f17 HV |
414 | base + HSIO_SERDES6G_DIG_CFG_MISC_CFG); |
415 | serdes6g_write(base, addr); | |
416 | } | |
417 | ||
418 | static void serdes_setup(struct luton_private *priv) | |
419 | { | |
420 | size_t mask; | |
421 | int i = 0; | |
422 | ||
423 | for (i = 0; i < MAX_PORT; ++i) { | |
424 | if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff) | |
425 | continue; | |
426 | ||
427 | mask = BIT(priv->ports[i].serdes_index); | |
428 | serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode); | |
429 | } | |
c5620aee HV |
430 | } |
431 | ||
432 | static int luton_switch_init(struct luton_private *priv) | |
433 | { | |
434 | setbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1)); | |
435 | clrbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1)); | |
436 | ||
437 | /* Reset switch & memories */ | |
438 | writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT, | |
439 | priv->regs[SYS] + SYS_SYSTEM_RST_CFG); | |
440 | ||
441 | /* Wait to complete */ | |
442 | if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, | |
443 | SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) { | |
444 | printf("Timeout in memory reset\n"); | |
445 | } | |
446 | ||
447 | /* Enable switch core */ | |
448 | setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, | |
449 | SYS_SYSTEM_RST_CORE_ENA); | |
450 | ||
7e323f17 HV |
451 | /* Setup the Serdes macros */ |
452 | serdes_setup(priv); | |
c5620aee HV |
453 | |
454 | return 0; | |
455 | } | |
456 | ||
457 | static int luton_initialize(struct luton_private *priv) | |
458 | { | |
459 | int ret, i; | |
460 | ||
461 | /* Initialize switch memories, enable core */ | |
462 | ret = luton_switch_init(priv); | |
463 | if (ret) | |
464 | return ret; | |
465 | ||
466 | /* | |
467 | * Disable port-to-port by switching | |
468 | * Put front ports in "port isolation modes" - i.e. they can't send | |
469 | * to other ports - via the PGID sorce masks. | |
470 | */ | |
471 | for (i = 0; i < MAX_PORT; i++) | |
472 | writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i)); | |
473 | ||
474 | /* Flush queues */ | |
475 | mscc_flush(priv->regs[QS], luton_regs_qs); | |
476 | ||
477 | /* Setup frame ageing - "2 sec" - The unit is 4ns on Luton*/ | |
478 | writel(2000000000 / 4, | |
479 | priv->regs[SYS] + SYS_FRM_AGING); | |
480 | ||
7e323f17 | 481 | for (i = 0; i < MAX_PORT; i++) { |
c5620aee HV |
482 | if (i < PORT10) |
483 | luton_gmii_port_init(priv, i); | |
484 | else | |
485 | if (i == PORT10 || i == PORT11) | |
486 | luton_port_init(priv, i); | |
487 | else | |
488 | luton_ext_port_init(priv, i); | |
489 | } | |
490 | ||
491 | luton_cpu_capture_setup(priv); | |
492 | ||
493 | return 0; | |
494 | } | |
495 | ||
496 | static int luton_write_hwaddr(struct udevice *dev) | |
497 | { | |
498 | struct luton_private *priv = dev_get_priv(dev); | |
499 | struct eth_pdata *pdata = dev_get_platdata(dev); | |
500 | ||
501 | mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table, | |
502 | pdata->enetaddr, PGID_UNICAST); | |
503 | ||
504 | writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST)); | |
505 | ||
506 | return 0; | |
507 | } | |
508 | ||
509 | static int luton_start(struct udevice *dev) | |
510 | { | |
511 | struct luton_private *priv = dev_get_priv(dev); | |
512 | struct eth_pdata *pdata = dev_get_platdata(dev); | |
513 | const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, | |
514 | 0xff }; | |
515 | int ret; | |
516 | ||
517 | ret = luton_initialize(priv); | |
518 | if (ret) | |
519 | return ret; | |
520 | ||
521 | /* Set MAC address tables entries for CPU redirection */ | |
522 | mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table, | |
523 | mac, PGID_BROADCAST); | |
524 | ||
525 | writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK, | |
526 | priv->regs[ANA] + ANA_PGID(PGID_BROADCAST)); | |
527 | ||
528 | mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table, | |
529 | pdata->enetaddr, PGID_UNICAST); | |
530 | ||
531 | writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST)); | |
532 | ||
533 | return 0; | |
534 | } | |
535 | ||
536 | static int luton_send(struct udevice *dev, void *packet, int length) | |
537 | { | |
538 | struct luton_private *priv = dev_get_priv(dev); | |
539 | u32 ifh[IFH_LEN]; | |
540 | int port = BIT(0); /* use port 0 */ | |
541 | u32 *buf = packet; | |
542 | ||
543 | ifh[0] = IFH_INJ_BYPASS | port; | |
544 | ifh[1] = (IFH_TAG_TYPE_C << 16); | |
545 | ||
546 | return mscc_send(priv->regs[QS], luton_regs_qs, | |
547 | ifh, IFH_LEN, buf, length); | |
548 | } | |
549 | ||
550 | static int luton_recv(struct udevice *dev, int flags, uchar **packetp) | |
551 | { | |
552 | struct luton_private *priv = dev_get_priv(dev); | |
553 | u32 *rxbuf = (u32 *)net_rx_packets[0]; | |
554 | int byte_cnt = 0; | |
555 | ||
556 | byte_cnt = mscc_recv(priv->regs[QS], luton_regs_qs, rxbuf, IFH_LEN, | |
557 | true); | |
558 | ||
559 | *packetp = net_rx_packets[0]; | |
560 | ||
561 | return byte_cnt; | |
562 | } | |
563 | ||
7e323f17 HV |
564 | static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size) |
565 | { | |
566 | int i = 0; | |
567 | ||
568 | for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i) | |
569 | if (miim[i].miim_base == base && miim[i].miim_size == size) | |
570 | return miim[i].bus; | |
571 | ||
572 | return NULL; | |
573 | } | |
574 | ||
575 | static void add_port_entry(struct luton_private *priv, size_t index, | |
576 | size_t phy_addr, struct mii_dev *bus, | |
577 | u8 serdes_index, u8 phy_mode) | |
578 | { | |
579 | priv->ports[index].phy_addr = phy_addr; | |
580 | priv->ports[index].bus = bus; | |
581 | priv->ports[index].serdes_index = serdes_index; | |
582 | priv->ports[index].phy_mode = phy_mode; | |
583 | } | |
584 | ||
c5620aee HV |
585 | static int luton_probe(struct udevice *dev) |
586 | { | |
587 | struct luton_private *priv = dev_get_priv(dev); | |
7e323f17 HV |
588 | int i, ret; |
589 | struct resource res; | |
590 | fdt32_t faddr; | |
591 | phys_addr_t addr_base; | |
592 | unsigned long addr_size; | |
593 | ofnode eth_node, node, mdio_node; | |
594 | size_t phy_addr; | |
595 | struct mii_dev *bus; | |
596 | struct ofnode_phandle_args phandle; | |
597 | struct phy_device *phy; | |
c5620aee HV |
598 | |
599 | if (!priv) | |
600 | return -EINVAL; | |
601 | ||
7e323f17 HV |
602 | /* Get registers and map them to the private structure */ |
603 | for (i = 0; i < ARRAY_SIZE(regs_names); i++) { | |
604 | priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]); | |
605 | if (!priv->regs[i]) { | |
c5620aee HV |
606 | debug |
607 | ("Error can't get regs base addresses for %s\n", | |
7e323f17 | 608 | regs_names[i]); |
c5620aee HV |
609 | return -ENOMEM; |
610 | } | |
611 | } | |
612 | ||
613 | /* Release reset in the CU-PHY */ | |
614 | writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST); | |
615 | ||
616 | /* Ports with ext phy don't need to reset clk */ | |
7e323f17 | 617 | for (i = 0; i < MAX_INT_PORT; i++) { |
c5620aee HV |
618 | if (i < PORT10) |
619 | clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK, | |
620 | DEV_GMII_PORT_MODE_CLK_PHY_RST); | |
621 | else | |
622 | clrbits_le32(priv->regs[i] + DEV_PORT_MODE_CLK, | |
623 | DEV_PORT_MODE_CLK_PHY_RST); | |
624 | } | |
625 | ||
626 | /* Wait for internal PHY to be ready */ | |
627 | if (wait_for_bit_le32(priv->regs[GCB] + GCB_MISC_STAT, | |
628 | GCB_MISC_STAT_PHY_READY, true, 500, false)) | |
629 | return -EACCES; | |
630 | ||
c5620aee | 631 | |
7e323f17 HV |
632 | /* Initialize miim buses */ |
633 | memset(&miim, 0x0, sizeof(miim) * LUTON_MIIM_BUS_COUNT); | |
634 | ||
635 | /* iterate all the ports and find out on which bus they are */ | |
636 | i = 0; | |
637 | eth_node = dev_read_first_subnode(dev); | |
638 | for (node = ofnode_first_subnode(eth_node); | |
639 | ofnode_valid(node); | |
640 | node = ofnode_next_subnode(node)) { | |
641 | if (ofnode_read_resource(node, 0, &res)) | |
642 | return -ENOMEM; | |
643 | i = res.start; | |
644 | ||
645 | ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL, | |
646 | 0, 0, &phandle); | |
647 | if (ret) | |
648 | continue; | |
649 | ||
650 | /* Get phy address on mdio bus */ | |
651 | if (ofnode_read_resource(phandle.node, 0, &res)) | |
652 | return -ENOMEM; | |
653 | phy_addr = res.start; | |
654 | ||
655 | /* Get mdio node */ | |
656 | mdio_node = ofnode_get_parent(phandle.node); | |
657 | ||
658 | if (ofnode_read_resource(mdio_node, 0, &res)) | |
659 | return -ENOMEM; | |
660 | faddr = cpu_to_fdt32(res.start); | |
661 | ||
662 | addr_base = ofnode_translate_address(mdio_node, &faddr); | |
663 | addr_size = res.end - res.start; | |
664 | ||
665 | /* If the bus is new then create a new bus */ | |
666 | if (!get_mdiobus(addr_base, addr_size)) | |
667 | priv->bus[miim_count] = | |
61243678 HV |
668 | mscc_mdiobus_init(miim, &miim_count, addr_base, |
669 | addr_size); | |
7e323f17 HV |
670 | |
671 | /* Connect mdio bus with the port */ | |
672 | bus = get_mdiobus(addr_base, addr_size); | |
673 | ||
674 | /* Get serdes info */ | |
675 | ret = ofnode_parse_phandle_with_args(node, "phys", NULL, | |
676 | 3, 0, &phandle); | |
677 | if (ret) | |
678 | add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff); | |
679 | else | |
680 | add_port_entry(priv, i, phy_addr, bus, phandle.args[1], | |
681 | phandle.args[2]); | |
682 | } | |
683 | ||
684 | for (i = 0; i < MAX_PORT; i++) { | |
685 | if (!priv->ports[i].bus) | |
686 | continue; | |
687 | ||
688 | phy = phy_connect(priv->ports[i].bus, | |
689 | priv->ports[i].phy_addr, dev, | |
690 | PHY_INTERFACE_MODE_NONE); | |
691 | if (phy && i >= MAX_INT_PORT) | |
692 | board_phy_config(phy); | |
c5620aee HV |
693 | } |
694 | ||
695 | /* | |
696 | * coma_mode is need on only one phy, because all the other phys | |
697 | * will be affected. | |
698 | */ | |
7e323f17 HV |
699 | mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10); |
700 | mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800); | |
701 | mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0); | |
c5620aee HV |
702 | |
703 | return 0; | |
704 | } | |
705 | ||
706 | static int luton_remove(struct udevice *dev) | |
707 | { | |
708 | struct luton_private *priv = dev_get_priv(dev); | |
709 | int i; | |
710 | ||
7e323f17 | 711 | for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) { |
c5620aee HV |
712 | mdio_unregister(priv->bus[i]); |
713 | mdio_free(priv->bus[i]); | |
714 | } | |
715 | ||
716 | return 0; | |
717 | } | |
718 | ||
719 | static const struct eth_ops luton_ops = { | |
720 | .start = luton_start, | |
721 | .stop = luton_stop, | |
722 | .send = luton_send, | |
723 | .recv = luton_recv, | |
724 | .write_hwaddr = luton_write_hwaddr, | |
725 | }; | |
726 | ||
727 | static const struct udevice_id mscc_luton_ids[] = { | |
728 | {.compatible = "mscc,vsc7527-switch", }, | |
729 | { /* Sentinel */ } | |
730 | }; | |
731 | ||
732 | U_BOOT_DRIVER(luton) = { | |
733 | .name = "luton-switch", | |
734 | .id = UCLASS_ETH, | |
735 | .of_match = mscc_luton_ids, | |
736 | .probe = luton_probe, | |
737 | .remove = luton_remove, | |
738 | .ops = &luton_ops, | |
739 | .priv_auto_alloc_size = sizeof(struct luton_private), | |
740 | .platdata_auto_alloc_size = sizeof(struct eth_pdata), | |
741 | }; |