]> Git Repo - u-boot.git/blame - drivers/net/mscc_eswitch/luton_switch.c
dm: core: Create a new header file for 'compat' features
[u-boot.git] / drivers / net / mscc_eswitch / luton_switch.c
CommitLineData
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
140static 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
151enum 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
169struct 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
176struct 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
182static 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
190static 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
196static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT];
197static int miim_count = -1;
c5620aee 198
c5620aee
HV
199static 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
211static 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
252static 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
274static 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
296static 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 343static 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
356static 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
418static 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
432static 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
457static 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
496static 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
509static 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
536static 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
550static 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
564static 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
575static 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
585static 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
706static 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
719static 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
727static const struct udevice_id mscc_luton_ids[] = {
728 {.compatible = "mscc,vsc7527-switch", },
729 { /* Sentinel */ }
730};
731
732U_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};
This page took 0.12136 seconds and 4 git commands to generate.