blob: 5e4f00c4f4d943505273b884e139158bc0c639ba [file] [log] [blame]
Horatiu Vultura4097192019-01-31 15:30:39 +01001// 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>
Simon Glass9bc15642020-02-03 07:36:16 -07009#include <malloc.h>
Horatiu Vultura4097192019-01-31 15:30:39 +010010#include <dm/of_access.h>
11#include <dm/of_addr.h>
12#include <fdt_support.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060013#include <linux/bitops.h>
Horatiu Vultura4097192019-01-31 15:30:39 +010014#include <linux/io.h>
15#include <linux/ioport.h>
16#include <miiphy.h>
17#include <net.h>
18#include <wait_bit.h>
19
Horatiu Vultura4097192019-01-31 15:30:39 +010020#include "mscc_xfer.h"
21#include "mscc_mac_table.h"
Horatiu Vultur6fbf1612019-06-09 15:27:29 +020022#include "mscc_miim.h"
Horatiu Vultur7afd7942019-05-01 13:16:58 +020023
Horatiu Vultura4097192019-01-31 15:30:39 +010024#define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x))
25#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
26#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
27#define ANA_PORT_CPU_FWD_CFG(x) (0x50 + 0x80 * (x))
28#define ANA_PORT_CPU_FWD_CFG_SRC_COPY_ENA BIT(1)
29#define ANA_PORT_PORT_CFG(x) (0x60 + 0x80 * (x))
30#define ANA_PORT_PORT_CFG_RECV_ENA BIT(5)
31#define ANA_PGID(x) (0x1000 + 4 * (x))
32
33#define SYS_FRM_AGING 0x8300
34
35#define SYS_SYSTEM_RST_CFG 0x81b0
36#define SYS_SYSTEM_RST_MEM_INIT BIT(0)
37#define SYS_SYSTEM_RST_MEM_ENA BIT(1)
38#define SYS_SYSTEM_RST_CORE_ENA BIT(2)
39#define SYS_PORT_MODE(x) (0x81bc + 0x4 * (x))
40#define SYS_PORT_MODE_INCL_INJ_HDR BIT(0)
41#define SYS_SWITCH_PORT_MODE(x) (0x8294 + 0x4 * (x))
42#define SYS_SWITCH_PORT_MODE_PORT_ENA BIT(3)
43#define SYS_EGR_NO_SHARING 0x8378
44#define SYS_SCH_CPU 0x85a0
45
46#define REW_PORT_CFG(x) (0x8 + 0x80 * (x))
47#define REW_PORT_CFG_IFH_INSERT_ENA BIT(7)
48
49#define GCB_DEVCPU_RST_SOFT_CHIP_RST 0x90
50#define GCB_DEVCPU_RST_SOFT_CHIP_RST_SOFT_PHY BIT(1)
51#define GCB_MISC_STAT 0x11c
52#define GCB_MISC_STAT_PHY_READY BIT(3)
53
54#define QS_XTR_MAP(x) (0x10 + 4 * (x))
55#define QS_XTR_MAP_GRP BIT(4)
56#define QS_XTR_MAP_ENA BIT(0)
57
58#define HSIO_PLL5G_CFG_PLL5G_CFG2 0x8
59
60#define HSIO_RCOMP_CFG_CFG0 0x20
61#define HSIO_RCOMP_CFG_CFG0_MODE_SEL(x) ((x) << 8)
62#define HSIO_RCOMP_CFG_CFG0_RUN_CAL BIT(12)
63#define HSIO_RCOMP_STATUS 0x24
64#define HSIO_RCOMP_STATUS_BUSY BIT(12)
65#define HSIO_RCOMP_STATUS_RCOMP_M GENMASK(3, 0)
66#define HSIO_SERDES6G_ANA_CFG_DES_CFG 0x64
67#define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(x) ((x) << 1)
68#define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(x) ((x) << 5)
69#define HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(x) ((x) << 10)
70#define HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(x) ((x) << 13)
71#define HSIO_SERDES6G_ANA_CFG_IB_CFG 0x68
72#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(x) (x)
73#define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(x) ((x) << 4)
74#define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(x) ((x) << 7)
75#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(x) ((x) << 9)
76#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(x) ((x) << 14)
77#define HSIO_SERDES6G_ANA_CFG_IB_CFG1 0x6c
78#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST BIT(0)
79#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC BIT(2)
80#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC BIT(3)
81#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE BIT(6)
82#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF BIT(7)
83#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(x) ((x) << 8)
84#define HSIO_SERDES6G_ANA_CFG_OB_CFG 0x70
85#define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(x) ((x) << 4)
86#define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H BIT(8)
87#define HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(x) ((x) << 23)
88#define HSIO_SERDES6G_ANA_CFG_OB_CFG_POL BIT(29)
89#define HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE BIT(30)
90#define HSIO_SERDES6G_ANA_CFG_OB_CFG1 0x74
91#define HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(x) (x)
92#define HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(x) ((x) << 6)
93#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG 0x7c
94#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(x) (x)
95#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE BIT(18)
96#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST BIT(31)
97#define HSIO_SERDES6G_ANA_CFG_PLL_CFG 0x80
98#define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA BIT(7)
99#define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
100#define HSIO_SERDES6G_ANA_CFG_SER_CFG 0x84
101#define HSIO_SERDES6G_DIG_CFG_MISC_CFG 0x88
102#define HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST BIT(0)
103#define HSIO_MCB_SERDES6G_CFG 0xac
104#define HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT BIT(31)
105#define HSIO_MCB_SERDES6G_CFG_ADDR(x) (x)
106
107#define DEV_GMII_PORT_MODE_CLK 0x0
108#define DEV_GMII_PORT_MODE_CLK_PHY_RST BIT(0)
109#define DEV_GMII_MAC_CFG_MAC_ENA 0xc
110#define DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
111#define DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
112
113#define DEV_PORT_MODE_CLK 0x4
114#define DEV_PORT_MODE_CLK_PHY_RST BIT(2)
115#define DEV_PORT_MODE_CLK_LINK_SPEED_1000 1
116#define DEV_MAC_CFG_MAC_ENA 0x10
117#define DEV_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
118#define DEV_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
119#define DEV_MAC_CFG_MAC_IFG 0x24
120#define DEV_MAC_CFG_MAC_IFG_TX_IFG(x) ((x) << 8)
121#define DEV_MAC_CFG_MAC_IFG_RX_IFG2(x) ((x) << 4)
122#define DEV_MAC_CFG_MAC_IFG_RX_IFG1(x) (x)
123#define DEV_PCS1G_CFG_PCS1G_CFG 0x40
124#define DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA BIT(0)
125#define DEV_PCS1G_CFG_PCS1G_MODE 0x44
126#define DEV_PCS1G_CFG_PCS1G_SD 0x48
127#define DEV_PCS1G_CFG_PCS1G_ANEG 0x4c
128#define DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16)
129
130#define IFH_INJ_BYPASS BIT(31)
131#define IFH_TAG_TYPE_C 0
132#define MAC_VID 1
133#define CPU_PORT 26
134#define INTERNAL_PORT_MSK 0xFFFFFF
135#define IFH_LEN 2
136#define ETH_ALEN 6
137#define PGID_BROADCAST 28
138#define PGID_UNICAST 29
139#define PGID_SRC 80
140
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200141static const char * const regs_names[] = {
142 "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
143 "port8", "port9", "port10", "port11", "port12", "port13", "port14",
144 "port15", "port16", "port17", "port18", "port19", "port20", "port21",
145 "port22", "port23",
146 "sys", "ana", "rew", "gcb", "qs", "hsio",
147};
148
149#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
150#define MAX_PORT 24
151
152enum luton_ctrl_regs {
153 SYS = MAX_PORT,
Horatiu Vultura4097192019-01-31 15:30:39 +0100154 ANA,
155 REW,
156 GCB,
157 QS,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200158 HSIO
Horatiu Vultura4097192019-01-31 15:30:39 +0100159};
160
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200161#define MIN_INT_PORT 0
162#define PORT10 10
163#define PORT11 11
164#define MAX_INT_PORT 12
165#define MIN_EXT_PORT MAX_INT_PORT
166#define MAX_EXT_PORT MAX_PORT
Horatiu Vultura4097192019-01-31 15:30:39 +0100167
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200168#define LUTON_MIIM_BUS_COUNT 2
Horatiu Vultura4097192019-01-31 15:30:39 +0100169
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200170struct luton_phy_port_t {
171 size_t phy_addr;
172 struct mii_dev *bus;
173 u8 serdes_index;
174 u8 phy_mode;
Horatiu Vultura4097192019-01-31 15:30:39 +0100175};
176
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200177struct luton_private {
178 void __iomem *regs[REGS_NAMES_COUNT];
179 struct mii_dev *bus[LUTON_MIIM_BUS_COUNT];
180 struct luton_phy_port_t ports[MAX_PORT];
Horatiu Vultura4097192019-01-31 15:30:39 +0100181};
182
Horatiu Vultura4097192019-01-31 15:30:39 +0100183static const unsigned long luton_regs_qs[] = {
184 [MSCC_QS_XTR_RD] = 0x18,
185 [MSCC_QS_XTR_FLUSH] = 0x28,
186 [MSCC_QS_XTR_DATA_PRESENT] = 0x2c,
187 [MSCC_QS_INJ_WR] = 0x3c,
188 [MSCC_QS_INJ_CTRL] = 0x44,
189};
190
191static const unsigned long luton_regs_ana_table[] = {
192 [MSCC_ANA_TABLES_MACHDATA] = 0x11b0,
193 [MSCC_ANA_TABLES_MACLDATA] = 0x11b4,
194 [MSCC_ANA_TABLES_MACACCESS] = 0x11b8,
195};
196
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200197static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT];
198static int miim_count = -1;
Horatiu Vultura4097192019-01-31 15:30:39 +0100199
Horatiu Vultura4097192019-01-31 15:30:39 +0100200static void luton_stop(struct udevice *dev)
201{
202 struct luton_private *priv = dev_get_priv(dev);
203
204 /*
205 * Switch core only reset affects VCORE-III bus and MIPS frequency
206 * and thereby also the DDR SDRAM controller. The workaround is to
207 * not to redirect any trafic to the CPU after the data transfer.
208 */
209 writel(GENMASK(9, 2), priv->regs[SYS] + SYS_SCH_CPU);
210}
211
212static void luton_cpu_capture_setup(struct luton_private *priv)
213{
214 int i;
215
216 /* map the 8 CPU extraction queues to CPU port 26 */
217 writel(0x0, priv->regs[SYS] + SYS_SCH_CPU);
218
219 for (i = 0; i <= 1; i++) {
220 /*
221 * One to one mapping from CPU Queue number to Group extraction
222 * number
223 */
224 writel(QS_XTR_MAP_ENA | (QS_XTR_MAP_GRP * i),
225 priv->regs[QS] + QS_XTR_MAP(i));
226
227 /* Enable IFH insertion/parsing on CPU ports */
228 setbits_le32(priv->regs[REW] + REW_PORT_CFG(CPU_PORT + i),
229 REW_PORT_CFG_IFH_INSERT_ENA);
230
231 /* Enable IFH parsing on CPU port 0 and 1 */
232 setbits_le32(priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i),
233 SYS_PORT_MODE_INCL_INJ_HDR);
234 }
235
236 /* Make VLAN aware for CPU traffic */
237 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
238 ANA_PORT_VLAN_CFG_POP_CNT(1) |
239 MAC_VID,
240 priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
241
242 /* Disable learning (only RECV_ENA must be set) */
243 writel(ANA_PORT_PORT_CFG_RECV_ENA,
244 priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
245
246 /* Enable switching to/from cpu port */
247 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(CPU_PORT),
248 SYS_SWITCH_PORT_MODE_PORT_ENA);
249
250 setbits_le32(priv->regs[SYS] + SYS_EGR_NO_SHARING, BIT(CPU_PORT));
251}
252
253static void luton_gmii_port_init(struct luton_private *priv, int port)
254{
255 void __iomem *regs = priv->regs[port];
256
257 writel(0, regs + DEV_GMII_PORT_MODE_CLK);
258
259 /* Enable MAC RX and TX */
260 writel(DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA |
261 DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA,
262 regs + DEV_GMII_MAC_CFG_MAC_ENA);
263
264 /* Make VLAN aware for CPU traffic */
265 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
266 ANA_PORT_VLAN_CFG_POP_CNT(1) |
267 MAC_VID,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200268 priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
Horatiu Vultura4097192019-01-31 15:30:39 +0100269
270 /* Enable switching to/from port */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200271 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
Horatiu Vultura4097192019-01-31 15:30:39 +0100272 SYS_SWITCH_PORT_MODE_PORT_ENA);
273}
274
275static void luton_port_init(struct luton_private *priv, int port)
276{
277 void __iomem *regs = priv->regs[port];
278
279 writel(0, regs + DEV_PORT_MODE_CLK);
280
281 /* Enable MAC RX and TX */
282 writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
283 DEV_MAC_CFG_MAC_ENA_TX_ENA,
284 regs + DEV_MAC_CFG_MAC_ENA);
285
286 /* Make VLAN aware for CPU traffic */
287 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
288 ANA_PORT_VLAN_CFG_POP_CNT(1) |
289 MAC_VID,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200290 priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
Horatiu Vultura4097192019-01-31 15:30:39 +0100291
292 /* Enable switching to/from port */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200293 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
Horatiu Vultura4097192019-01-31 15:30:39 +0100294 SYS_SWITCH_PORT_MODE_PORT_ENA);
295}
296
297static void luton_ext_port_init(struct luton_private *priv, int port)
298{
299 void __iomem *regs = priv->regs[port];
300
301 /* Enable PCS */
302 writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
303 regs + DEV_PCS1G_CFG_PCS1G_CFG);
304
305 /* Disable Signal Detect */
306 writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
307
308 /* Enable MAC RX and TX */
309 writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
310 DEV_MAC_CFG_MAC_ENA_TX_ENA,
311 regs + DEV_MAC_CFG_MAC_ENA);
312
313 /* Clear sgmii_mode_ena */
314 writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
315
316 /*
317 * Clear sw_resolve_ena(bit 0) and set adv_ability to
318 * something meaningful just in case
319 */
320 writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
321 regs + DEV_PCS1G_CFG_PCS1G_ANEG);
322
323 /* Set MAC IFG Gaps */
324 writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(7) |
325 DEV_MAC_CFG_MAC_IFG_RX_IFG1(1) |
326 DEV_MAC_CFG_MAC_IFG_RX_IFG2(5),
327 regs + DEV_MAC_CFG_MAC_IFG);
328
329 /* Set link speed and release all resets */
330 writel(DEV_PORT_MODE_CLK_LINK_SPEED_1000,
331 regs + DEV_PORT_MODE_CLK);
332
333 /* Make VLAN aware for CPU traffic */
334 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
335 ANA_PORT_VLAN_CFG_POP_CNT(1) |
336 MAC_VID,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200337 priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
Horatiu Vultura4097192019-01-31 15:30:39 +0100338
339 /* Enable switching to/from port */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200340 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
Horatiu Vultura4097192019-01-31 15:30:39 +0100341 SYS_SWITCH_PORT_MODE_PORT_ENA);
342}
343
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200344static void serdes6g_write(void __iomem *base, u32 addr)
Horatiu Vultura4097192019-01-31 15:30:39 +0100345{
346 u32 data;
347
348 writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
349 HSIO_MCB_SERDES6G_CFG_ADDR(addr),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200350 base + HSIO_MCB_SERDES6G_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100351
352 do {
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200353 data = readl(base + HSIO_MCB_SERDES6G_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100354 } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
Horatiu Vultura4097192019-01-31 15:30:39 +0100355}
356
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200357static void serdes6g_setup(void __iomem *base, uint32_t addr,
358 phy_interface_t interface)
Horatiu Vultura4097192019-01-31 15:30:39 +0100359{
360 writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
361 HSIO_RCOMP_CFG_CFG0_RUN_CAL,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200362 base + HSIO_RCOMP_CFG_CFG0);
Horatiu Vultura4097192019-01-31 15:30:39 +0100363
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200364 while (readl(base + HSIO_RCOMP_STATUS) &
Horatiu Vultura4097192019-01-31 15:30:39 +0100365 HSIO_RCOMP_STATUS_BUSY)
366 ;
367
368 writel(HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(0xb) |
369 HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H |
370 HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
371 HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
372 HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200373 base + HSIO_SERDES6G_ANA_CFG_OB_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100374 writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
375 HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200376 base + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
Horatiu Vultura4097192019-01-31 15:30:39 +0100377 writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
378 HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
379 HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
380 HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
381 HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200382 base + HSIO_SERDES6G_ANA_CFG_IB_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100383 writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
384 HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
385 HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
386 HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
387 HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
388 HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200389 base + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
Horatiu Vultura4097192019-01-31 15:30:39 +0100390 writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
391 HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
392 HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
393 HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200394 base + HSIO_SERDES6G_ANA_CFG_DES_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100395 writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
396 HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200397 base + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100398 writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
399 HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200400 base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100401 /*
402 * There are 4 serdes6g, configure all except serdes6g0, therefore
403 * the address is b1110
404 */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200405 serdes6g_write(base, addr);
Horatiu Vultura4097192019-01-31 15:30:39 +0100406
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200407 writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
Horatiu Vultura4097192019-01-31 15:30:39 +0100408 HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200409 base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
410 serdes6g_write(base, addr);
Horatiu Vultura4097192019-01-31 15:30:39 +0100411
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200412 clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
Horatiu Vultura4097192019-01-31 15:30:39 +0100413 HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
414 writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200415 base + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
416 serdes6g_write(base, addr);
Horatiu Vultura4097192019-01-31 15:30:39 +0100417}
418
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200419static void serdes_setup(struct luton_private *priv)
420{
421 size_t mask;
422 int i = 0;
423
424 for (i = 0; i < MAX_PORT; ++i) {
425 if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
426 continue;
427
428 mask = BIT(priv->ports[i].serdes_index);
429 serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode);
430 }
431}
432
Horatiu Vultura4097192019-01-31 15:30:39 +0100433static int luton_switch_init(struct luton_private *priv)
434{
435 setbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
436 clrbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
437
438 /* Reset switch & memories */
439 writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
440 priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
441
442 /* Wait to complete */
443 if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
444 SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
445 printf("Timeout in memory reset\n");
446 }
447
448 /* Enable switch core */
449 setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
450 SYS_SYSTEM_RST_CORE_ENA);
451
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200452 /* Setup the Serdes macros */
453 serdes_setup(priv);
Horatiu Vultura4097192019-01-31 15:30:39 +0100454
455 return 0;
456}
457
458static int luton_initialize(struct luton_private *priv)
459{
460 int ret, i;
461
462 /* Initialize switch memories, enable core */
463 ret = luton_switch_init(priv);
464 if (ret)
465 return ret;
466
467 /*
468 * Disable port-to-port by switching
469 * Put front ports in "port isolation modes" - i.e. they can't send
470 * to other ports - via the PGID sorce masks.
471 */
472 for (i = 0; i < MAX_PORT; i++)
473 writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
474
475 /* Flush queues */
476 mscc_flush(priv->regs[QS], luton_regs_qs);
477
478 /* Setup frame ageing - "2 sec" - The unit is 4ns on Luton*/
479 writel(2000000000 / 4,
480 priv->regs[SYS] + SYS_FRM_AGING);
481
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200482 for (i = 0; i < MAX_PORT; i++) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100483 if (i < PORT10)
484 luton_gmii_port_init(priv, i);
485 else
486 if (i == PORT10 || i == PORT11)
487 luton_port_init(priv, i);
488 else
489 luton_ext_port_init(priv, i);
490 }
491
492 luton_cpu_capture_setup(priv);
493
494 return 0;
495}
496
497static int luton_write_hwaddr(struct udevice *dev)
498{
499 struct luton_private *priv = dev_get_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700500 struct eth_pdata *pdata = dev_get_plat(dev);
Horatiu Vultura4097192019-01-31 15:30:39 +0100501
502 mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
503 pdata->enetaddr, PGID_UNICAST);
504
505 writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
506
507 return 0;
508}
509
510static int luton_start(struct udevice *dev)
511{
512 struct luton_private *priv = dev_get_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700513 struct eth_pdata *pdata = dev_get_plat(dev);
Horatiu Vultura4097192019-01-31 15:30:39 +0100514 const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
515 0xff };
516 int ret;
517
518 ret = luton_initialize(priv);
519 if (ret)
520 return ret;
521
522 /* Set MAC address tables entries for CPU redirection */
523 mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
524 mac, PGID_BROADCAST);
525
526 writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
527 priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
528
529 mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
530 pdata->enetaddr, PGID_UNICAST);
531
532 writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
533
534 return 0;
535}
536
537static int luton_send(struct udevice *dev, void *packet, int length)
538{
539 struct luton_private *priv = dev_get_priv(dev);
540 u32 ifh[IFH_LEN];
541 int port = BIT(0); /* use port 0 */
542 u32 *buf = packet;
543
544 ifh[0] = IFH_INJ_BYPASS | port;
545 ifh[1] = (IFH_TAG_TYPE_C << 16);
546
547 return mscc_send(priv->regs[QS], luton_regs_qs,
548 ifh, IFH_LEN, buf, length);
549}
550
551static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
552{
553 struct luton_private *priv = dev_get_priv(dev);
554 u32 *rxbuf = (u32 *)net_rx_packets[0];
555 int byte_cnt = 0;
556
557 byte_cnt = mscc_recv(priv->regs[QS], luton_regs_qs, rxbuf, IFH_LEN,
558 true);
559
560 *packetp = net_rx_packets[0];
561
562 return byte_cnt;
563}
564
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200565static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
566{
567 int i = 0;
568
569 for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i)
570 if (miim[i].miim_base == base && miim[i].miim_size == size)
571 return miim[i].bus;
572
573 return NULL;
574}
575
576static void add_port_entry(struct luton_private *priv, size_t index,
577 size_t phy_addr, struct mii_dev *bus,
578 u8 serdes_index, u8 phy_mode)
579{
580 priv->ports[index].phy_addr = phy_addr;
581 priv->ports[index].bus = bus;
582 priv->ports[index].serdes_index = serdes_index;
583 priv->ports[index].phy_mode = phy_mode;
584}
585
Horatiu Vultura4097192019-01-31 15:30:39 +0100586static int luton_probe(struct udevice *dev)
587{
588 struct luton_private *priv = dev_get_priv(dev);
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200589 int i, ret;
590 struct resource res;
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200591 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;
Horatiu Vultura4097192019-01-31 15:30:39 +0100598
599 if (!priv)
600 return -EINVAL;
601
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200602 /* 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]) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100606 debug
607 ("Error can't get regs base addresses for %s\n",
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200608 regs_names[i]);
Horatiu Vultura4097192019-01-31 15:30:39 +0100609 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 */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200617 for (i = 0; i < MAX_INT_PORT; i++) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100618 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
Horatiu Vultura4097192019-01-31 15:30:39 +0100631
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200632 /* 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;
Patrick Delaunayf27c47d2021-05-21 12:24:59 +0200660 addr_base = res.start;
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200661 addr_size = res.end - res.start;
662
663 /* If the bus is new then create a new bus */
664 if (!get_mdiobus(addr_base, addr_size))
665 priv->bus[miim_count] =
Horatiu Vultur6fbf1612019-06-09 15:27:29 +0200666 mscc_mdiobus_init(miim, &miim_count, addr_base,
667 addr_size);
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200668
669 /* Connect mdio bus with the port */
670 bus = get_mdiobus(addr_base, addr_size);
671
672 /* Get serdes info */
673 ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
674 3, 0, &phandle);
675 if (ret)
676 add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
677 else
678 add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
679 phandle.args[2]);
680 }
681
682 for (i = 0; i < MAX_PORT; i++) {
683 if (!priv->ports[i].bus)
684 continue;
685
686 phy = phy_connect(priv->ports[i].bus,
687 priv->ports[i].phy_addr, dev,
Marek BehĂșn48631e42022-04-07 00:33:03 +0200688 PHY_INTERFACE_MODE_NA);
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200689 if (phy && i >= MAX_INT_PORT)
690 board_phy_config(phy);
Horatiu Vultura4097192019-01-31 15:30:39 +0100691 }
692
693 /*
694 * coma_mode is need on only one phy, because all the other phys
695 * will be affected.
696 */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200697 mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10);
698 mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800);
699 mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0);
Horatiu Vultura4097192019-01-31 15:30:39 +0100700
701 return 0;
702}
703
704static int luton_remove(struct udevice *dev)
705{
706 struct luton_private *priv = dev_get_priv(dev);
707 int i;
708
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200709 for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100710 mdio_unregister(priv->bus[i]);
711 mdio_free(priv->bus[i]);
712 }
713
714 return 0;
715}
716
717static const struct eth_ops luton_ops = {
718 .start = luton_start,
719 .stop = luton_stop,
720 .send = luton_send,
721 .recv = luton_recv,
722 .write_hwaddr = luton_write_hwaddr,
723};
724
725static const struct udevice_id mscc_luton_ids[] = {
726 {.compatible = "mscc,vsc7527-switch", },
727 { /* Sentinel */ }
728};
729
730U_BOOT_DRIVER(luton) = {
731 .name = "luton-switch",
732 .id = UCLASS_ETH,
733 .of_match = mscc_luton_ids,
734 .probe = luton_probe,
735 .remove = luton_remove,
736 .ops = &luton_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700737 .priv_auto = sizeof(struct luton_private),
Simon Glass71fa5b42020-12-03 16:55:18 -0700738 .plat_auto = sizeof(struct eth_pdata),
Horatiu Vultura4097192019-01-31 15:30:39 +0100739};