blob: 94852b06e745995d1867660f871444f47df7da63 [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>
9#include <dm/of_access.h>
10#include <dm/of_addr.h>
11#include <fdt_support.h>
12#include <linux/io.h>
13#include <linux/ioport.h>
14#include <miiphy.h>
15#include <net.h>
16#include <wait_bit.h>
17
Horatiu Vultura4097192019-01-31 15:30:39 +010018#include "mscc_xfer.h"
19#include "mscc_mac_table.h"
20
Horatiu Vultur7afd7942019-05-01 13:16:58 +020021#define GCB_MIIM_MII_STATUS 0x0
22#define GCB_MIIM_STAT_BUSY BIT(3)
23#define GCB_MIIM_MII_CMD 0x8
24#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1)
25#define GCB_MIIM_MII_CMD_OPR_READ BIT(2)
26#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4)
27#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20)
28#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25)
29#define GCB_MIIM_MII_CMD_VLD BIT(31)
30#define GCB_MIIM_DATA 0xC
31#define GCB_MIIM_DATA_ERROR (0x2 << 16)
32
Horatiu Vultura4097192019-01-31 15:30:39 +010033#define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x))
34#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
35#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
36#define ANA_PORT_CPU_FWD_CFG(x) (0x50 + 0x80 * (x))
37#define ANA_PORT_CPU_FWD_CFG_SRC_COPY_ENA BIT(1)
38#define ANA_PORT_PORT_CFG(x) (0x60 + 0x80 * (x))
39#define ANA_PORT_PORT_CFG_RECV_ENA BIT(5)
40#define ANA_PGID(x) (0x1000 + 4 * (x))
41
42#define SYS_FRM_AGING 0x8300
43
44#define SYS_SYSTEM_RST_CFG 0x81b0
45#define SYS_SYSTEM_RST_MEM_INIT BIT(0)
46#define SYS_SYSTEM_RST_MEM_ENA BIT(1)
47#define SYS_SYSTEM_RST_CORE_ENA BIT(2)
48#define SYS_PORT_MODE(x) (0x81bc + 0x4 * (x))
49#define SYS_PORT_MODE_INCL_INJ_HDR BIT(0)
50#define SYS_SWITCH_PORT_MODE(x) (0x8294 + 0x4 * (x))
51#define SYS_SWITCH_PORT_MODE_PORT_ENA BIT(3)
52#define SYS_EGR_NO_SHARING 0x8378
53#define SYS_SCH_CPU 0x85a0
54
55#define REW_PORT_CFG(x) (0x8 + 0x80 * (x))
56#define REW_PORT_CFG_IFH_INSERT_ENA BIT(7)
57
58#define GCB_DEVCPU_RST_SOFT_CHIP_RST 0x90
59#define GCB_DEVCPU_RST_SOFT_CHIP_RST_SOFT_PHY BIT(1)
60#define GCB_MISC_STAT 0x11c
61#define GCB_MISC_STAT_PHY_READY BIT(3)
62
63#define QS_XTR_MAP(x) (0x10 + 4 * (x))
64#define QS_XTR_MAP_GRP BIT(4)
65#define QS_XTR_MAP_ENA BIT(0)
66
67#define HSIO_PLL5G_CFG_PLL5G_CFG2 0x8
68
69#define HSIO_RCOMP_CFG_CFG0 0x20
70#define HSIO_RCOMP_CFG_CFG0_MODE_SEL(x) ((x) << 8)
71#define HSIO_RCOMP_CFG_CFG0_RUN_CAL BIT(12)
72#define HSIO_RCOMP_STATUS 0x24
73#define HSIO_RCOMP_STATUS_BUSY BIT(12)
74#define HSIO_RCOMP_STATUS_RCOMP_M GENMASK(3, 0)
75#define HSIO_SERDES6G_ANA_CFG_DES_CFG 0x64
76#define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(x) ((x) << 1)
77#define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(x) ((x) << 5)
78#define HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(x) ((x) << 10)
79#define HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(x) ((x) << 13)
80#define HSIO_SERDES6G_ANA_CFG_IB_CFG 0x68
81#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(x) (x)
82#define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(x) ((x) << 4)
83#define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(x) ((x) << 7)
84#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(x) ((x) << 9)
85#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(x) ((x) << 14)
86#define HSIO_SERDES6G_ANA_CFG_IB_CFG1 0x6c
87#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST BIT(0)
88#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC BIT(2)
89#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC BIT(3)
90#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE BIT(6)
91#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF BIT(7)
92#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(x) ((x) << 8)
93#define HSIO_SERDES6G_ANA_CFG_OB_CFG 0x70
94#define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(x) ((x) << 4)
95#define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H BIT(8)
96#define HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(x) ((x) << 23)
97#define HSIO_SERDES6G_ANA_CFG_OB_CFG_POL BIT(29)
98#define HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE BIT(30)
99#define HSIO_SERDES6G_ANA_CFG_OB_CFG1 0x74
100#define HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(x) (x)
101#define HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(x) ((x) << 6)
102#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG 0x7c
103#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(x) (x)
104#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE BIT(18)
105#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST BIT(31)
106#define HSIO_SERDES6G_ANA_CFG_PLL_CFG 0x80
107#define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA BIT(7)
108#define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
109#define HSIO_SERDES6G_ANA_CFG_SER_CFG 0x84
110#define HSIO_SERDES6G_DIG_CFG_MISC_CFG 0x88
111#define HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST BIT(0)
112#define HSIO_MCB_SERDES6G_CFG 0xac
113#define HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT BIT(31)
114#define HSIO_MCB_SERDES6G_CFG_ADDR(x) (x)
115
116#define DEV_GMII_PORT_MODE_CLK 0x0
117#define DEV_GMII_PORT_MODE_CLK_PHY_RST BIT(0)
118#define DEV_GMII_MAC_CFG_MAC_ENA 0xc
119#define DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
120#define DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
121
122#define DEV_PORT_MODE_CLK 0x4
123#define DEV_PORT_MODE_CLK_PHY_RST BIT(2)
124#define DEV_PORT_MODE_CLK_LINK_SPEED_1000 1
125#define DEV_MAC_CFG_MAC_ENA 0x10
126#define DEV_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
127#define DEV_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
128#define DEV_MAC_CFG_MAC_IFG 0x24
129#define DEV_MAC_CFG_MAC_IFG_TX_IFG(x) ((x) << 8)
130#define DEV_MAC_CFG_MAC_IFG_RX_IFG2(x) ((x) << 4)
131#define DEV_MAC_CFG_MAC_IFG_RX_IFG1(x) (x)
132#define DEV_PCS1G_CFG_PCS1G_CFG 0x40
133#define DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA BIT(0)
134#define DEV_PCS1G_CFG_PCS1G_MODE 0x44
135#define DEV_PCS1G_CFG_PCS1G_SD 0x48
136#define DEV_PCS1G_CFG_PCS1G_ANEG 0x4c
137#define DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16)
138
139#define IFH_INJ_BYPASS BIT(31)
140#define IFH_TAG_TYPE_C 0
141#define MAC_VID 1
142#define CPU_PORT 26
143#define INTERNAL_PORT_MSK 0xFFFFFF
144#define IFH_LEN 2
145#define ETH_ALEN 6
146#define PGID_BROADCAST 28
147#define PGID_UNICAST 29
148#define PGID_SRC 80
149
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200150static const char * const regs_names[] = {
151 "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
152 "port8", "port9", "port10", "port11", "port12", "port13", "port14",
153 "port15", "port16", "port17", "port18", "port19", "port20", "port21",
154 "port22", "port23",
155 "sys", "ana", "rew", "gcb", "qs", "hsio",
156};
157
158#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
159#define MAX_PORT 24
160
161enum luton_ctrl_regs {
162 SYS = MAX_PORT,
Horatiu Vultura4097192019-01-31 15:30:39 +0100163 ANA,
164 REW,
165 GCB,
166 QS,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200167 HSIO
Horatiu Vultura4097192019-01-31 15:30:39 +0100168};
169
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200170#define MIN_INT_PORT 0
171#define PORT10 10
172#define PORT11 11
173#define MAX_INT_PORT 12
174#define MIN_EXT_PORT MAX_INT_PORT
175#define MAX_EXT_PORT MAX_PORT
Horatiu Vultura4097192019-01-31 15:30:39 +0100176
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200177#define LUTON_MIIM_BUS_COUNT 2
Horatiu Vultura4097192019-01-31 15:30:39 +0100178
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200179struct luton_phy_port_t {
180 size_t phy_addr;
181 struct mii_dev *bus;
182 u8 serdes_index;
183 u8 phy_mode;
Horatiu Vultura4097192019-01-31 15:30:39 +0100184};
185
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200186struct luton_private {
187 void __iomem *regs[REGS_NAMES_COUNT];
188 struct mii_dev *bus[LUTON_MIIM_BUS_COUNT];
189 struct luton_phy_port_t ports[MAX_PORT];
Horatiu Vultura4097192019-01-31 15:30:39 +0100190};
191
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200192struct mscc_miim_dev {
193 void __iomem *regs;
194 phys_addr_t miim_base;
195 unsigned long miim_size;
196 struct mii_dev *bus;
Horatiu Vultura4097192019-01-31 15:30:39 +0100197};
198
199static const unsigned long luton_regs_qs[] = {
200 [MSCC_QS_XTR_RD] = 0x18,
201 [MSCC_QS_XTR_FLUSH] = 0x28,
202 [MSCC_QS_XTR_DATA_PRESENT] = 0x2c,
203 [MSCC_QS_INJ_WR] = 0x3c,
204 [MSCC_QS_INJ_CTRL] = 0x44,
205};
206
207static const unsigned long luton_regs_ana_table[] = {
208 [MSCC_ANA_TABLES_MACHDATA] = 0x11b0,
209 [MSCC_ANA_TABLES_MACLDATA] = 0x11b4,
210 [MSCC_ANA_TABLES_MACACCESS] = 0x11b8,
211};
212
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200213static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT];
214static int miim_count = -1;
Horatiu Vultura4097192019-01-31 15:30:39 +0100215
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200216static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
Horatiu Vultura4097192019-01-31 15:30:39 +0100217{
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200218 return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
219 GCB_MIIM_STAT_BUSY, false, 250, false);
220}
221
222static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
223{
224 struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
225 u32 val;
226 int ret;
227
228 ret = mscc_miim_wait_ready(miim);
229 if (ret)
230 goto out;
231
232 writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
233 GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
234 miim->regs + GCB_MIIM_MII_CMD);
235
236 ret = mscc_miim_wait_ready(miim);
237 if (ret)
238 goto out;
239
240 val = readl(miim->regs + GCB_MIIM_DATA);
241 if (val & GCB_MIIM_DATA_ERROR) {
242 ret = -EIO;
243 goto out;
244 }
245
246 ret = val & 0xFFFF;
247 out:
248 return ret;
249}
250
251static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
252 u16 val)
253{
254 struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
255 int ret;
256
257 ret = mscc_miim_wait_ready(miim);
258 if (ret < 0)
259 goto out;
260
261 writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
262 GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
263 GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
264 out:
265 return ret;
266}
267
268static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base,
269 unsigned long miim_size)
270{
Horatiu Vultura4097192019-01-31 15:30:39 +0100271 struct mii_dev *bus;
Horatiu Vultura4097192019-01-31 15:30:39 +0100272
273 bus = mdio_alloc();
274 if (!bus)
275 return NULL;
276
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200277 ++miim_count;
278 sprintf(bus->name, "miim-bus%d", miim_count);
Horatiu Vultura4097192019-01-31 15:30:39 +0100279
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200280 miim[miim_count].regs = ioremap(miim_base, miim_size);
281 miim[miim_count].miim_base = miim_base;
282 miim[miim_count].miim_size = miim_size;
283 bus->priv = &miim[miim_count];
Horatiu Vultura4097192019-01-31 15:30:39 +0100284 bus->read = mscc_miim_read;
285 bus->write = mscc_miim_write;
286
287 if (mdio_register(bus))
288 return NULL;
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200289
290 miim[miim_count].bus = bus;
291 return bus;
Horatiu Vultura4097192019-01-31 15:30:39 +0100292}
293
294static void luton_stop(struct udevice *dev)
295{
296 struct luton_private *priv = dev_get_priv(dev);
297
298 /*
299 * Switch core only reset affects VCORE-III bus and MIPS frequency
300 * and thereby also the DDR SDRAM controller. The workaround is to
301 * not to redirect any trafic to the CPU after the data transfer.
302 */
303 writel(GENMASK(9, 2), priv->regs[SYS] + SYS_SCH_CPU);
304}
305
306static void luton_cpu_capture_setup(struct luton_private *priv)
307{
308 int i;
309
310 /* map the 8 CPU extraction queues to CPU port 26 */
311 writel(0x0, priv->regs[SYS] + SYS_SCH_CPU);
312
313 for (i = 0; i <= 1; i++) {
314 /*
315 * One to one mapping from CPU Queue number to Group extraction
316 * number
317 */
318 writel(QS_XTR_MAP_ENA | (QS_XTR_MAP_GRP * i),
319 priv->regs[QS] + QS_XTR_MAP(i));
320
321 /* Enable IFH insertion/parsing on CPU ports */
322 setbits_le32(priv->regs[REW] + REW_PORT_CFG(CPU_PORT + i),
323 REW_PORT_CFG_IFH_INSERT_ENA);
324
325 /* Enable IFH parsing on CPU port 0 and 1 */
326 setbits_le32(priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i),
327 SYS_PORT_MODE_INCL_INJ_HDR);
328 }
329
330 /* Make VLAN aware for CPU traffic */
331 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
332 ANA_PORT_VLAN_CFG_POP_CNT(1) |
333 MAC_VID,
334 priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
335
336 /* Disable learning (only RECV_ENA must be set) */
337 writel(ANA_PORT_PORT_CFG_RECV_ENA,
338 priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
339
340 /* Enable switching to/from cpu port */
341 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(CPU_PORT),
342 SYS_SWITCH_PORT_MODE_PORT_ENA);
343
344 setbits_le32(priv->regs[SYS] + SYS_EGR_NO_SHARING, BIT(CPU_PORT));
345}
346
347static void luton_gmii_port_init(struct luton_private *priv, int port)
348{
349 void __iomem *regs = priv->regs[port];
350
351 writel(0, regs + DEV_GMII_PORT_MODE_CLK);
352
353 /* Enable MAC RX and TX */
354 writel(DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA |
355 DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA,
356 regs + DEV_GMII_MAC_CFG_MAC_ENA);
357
358 /* Make VLAN aware for CPU traffic */
359 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
360 ANA_PORT_VLAN_CFG_POP_CNT(1) |
361 MAC_VID,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200362 priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
Horatiu Vultura4097192019-01-31 15:30:39 +0100363
364 /* Enable switching to/from port */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200365 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
Horatiu Vultura4097192019-01-31 15:30:39 +0100366 SYS_SWITCH_PORT_MODE_PORT_ENA);
367}
368
369static void luton_port_init(struct luton_private *priv, int port)
370{
371 void __iomem *regs = priv->regs[port];
372
373 writel(0, regs + DEV_PORT_MODE_CLK);
374
375 /* Enable MAC RX and TX */
376 writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
377 DEV_MAC_CFG_MAC_ENA_TX_ENA,
378 regs + DEV_MAC_CFG_MAC_ENA);
379
380 /* Make VLAN aware for CPU traffic */
381 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
382 ANA_PORT_VLAN_CFG_POP_CNT(1) |
383 MAC_VID,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200384 priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
Horatiu Vultura4097192019-01-31 15:30:39 +0100385
386 /* Enable switching to/from port */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200387 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
Horatiu Vultura4097192019-01-31 15:30:39 +0100388 SYS_SWITCH_PORT_MODE_PORT_ENA);
389}
390
391static void luton_ext_port_init(struct luton_private *priv, int port)
392{
393 void __iomem *regs = priv->regs[port];
394
395 /* Enable PCS */
396 writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
397 regs + DEV_PCS1G_CFG_PCS1G_CFG);
398
399 /* Disable Signal Detect */
400 writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
401
402 /* Enable MAC RX and TX */
403 writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
404 DEV_MAC_CFG_MAC_ENA_TX_ENA,
405 regs + DEV_MAC_CFG_MAC_ENA);
406
407 /* Clear sgmii_mode_ena */
408 writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
409
410 /*
411 * Clear sw_resolve_ena(bit 0) and set adv_ability to
412 * something meaningful just in case
413 */
414 writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
415 regs + DEV_PCS1G_CFG_PCS1G_ANEG);
416
417 /* Set MAC IFG Gaps */
418 writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(7) |
419 DEV_MAC_CFG_MAC_IFG_RX_IFG1(1) |
420 DEV_MAC_CFG_MAC_IFG_RX_IFG2(5),
421 regs + DEV_MAC_CFG_MAC_IFG);
422
423 /* Set link speed and release all resets */
424 writel(DEV_PORT_MODE_CLK_LINK_SPEED_1000,
425 regs + DEV_PORT_MODE_CLK);
426
427 /* Make VLAN aware for CPU traffic */
428 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
429 ANA_PORT_VLAN_CFG_POP_CNT(1) |
430 MAC_VID,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200431 priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
Horatiu Vultura4097192019-01-31 15:30:39 +0100432
433 /* Enable switching to/from port */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200434 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
Horatiu Vultura4097192019-01-31 15:30:39 +0100435 SYS_SWITCH_PORT_MODE_PORT_ENA);
436}
437
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200438static void serdes6g_write(void __iomem *base, u32 addr)
Horatiu Vultura4097192019-01-31 15:30:39 +0100439{
440 u32 data;
441
442 writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
443 HSIO_MCB_SERDES6G_CFG_ADDR(addr),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200444 base + HSIO_MCB_SERDES6G_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100445
446 do {
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200447 data = readl(base + HSIO_MCB_SERDES6G_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100448 } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
Horatiu Vultura4097192019-01-31 15:30:39 +0100449}
450
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200451static void serdes6g_setup(void __iomem *base, uint32_t addr,
452 phy_interface_t interface)
Horatiu Vultura4097192019-01-31 15:30:39 +0100453{
454 writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
455 HSIO_RCOMP_CFG_CFG0_RUN_CAL,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200456 base + HSIO_RCOMP_CFG_CFG0);
Horatiu Vultura4097192019-01-31 15:30:39 +0100457
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200458 while (readl(base + HSIO_RCOMP_STATUS) &
Horatiu Vultura4097192019-01-31 15:30:39 +0100459 HSIO_RCOMP_STATUS_BUSY)
460 ;
461
462 writel(HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(0xb) |
463 HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H |
464 HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
465 HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
466 HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200467 base + HSIO_SERDES6G_ANA_CFG_OB_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100468 writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
469 HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200470 base + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
Horatiu Vultura4097192019-01-31 15:30:39 +0100471 writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
472 HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
473 HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
474 HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
475 HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200476 base + HSIO_SERDES6G_ANA_CFG_IB_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100477 writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
478 HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
479 HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
480 HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
481 HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
482 HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200483 base + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
Horatiu Vultura4097192019-01-31 15:30:39 +0100484 writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
485 HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
486 HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
487 HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200488 base + HSIO_SERDES6G_ANA_CFG_DES_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100489 writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
490 HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200491 base + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100492 writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
493 HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200494 base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100495 /*
496 * There are 4 serdes6g, configure all except serdes6g0, therefore
497 * the address is b1110
498 */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200499 serdes6g_write(base, addr);
Horatiu Vultura4097192019-01-31 15:30:39 +0100500
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200501 writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
Horatiu Vultura4097192019-01-31 15:30:39 +0100502 HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200503 base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
504 serdes6g_write(base, addr);
Horatiu Vultura4097192019-01-31 15:30:39 +0100505
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200506 clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
Horatiu Vultura4097192019-01-31 15:30:39 +0100507 HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
508 writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200509 base + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
510 serdes6g_write(base, addr);
Horatiu Vultura4097192019-01-31 15:30:39 +0100511}
512
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200513static void serdes_setup(struct luton_private *priv)
514{
515 size_t mask;
516 int i = 0;
517
518 for (i = 0; i < MAX_PORT; ++i) {
519 if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
520 continue;
521
522 mask = BIT(priv->ports[i].serdes_index);
523 serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode);
524 }
525}
526
Horatiu Vultura4097192019-01-31 15:30:39 +0100527static int luton_switch_init(struct luton_private *priv)
528{
529 setbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
530 clrbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
531
532 /* Reset switch & memories */
533 writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
534 priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
535
536 /* Wait to complete */
537 if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
538 SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
539 printf("Timeout in memory reset\n");
540 }
541
542 /* Enable switch core */
543 setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
544 SYS_SYSTEM_RST_CORE_ENA);
545
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200546 /* Setup the Serdes macros */
547 serdes_setup(priv);
Horatiu Vultura4097192019-01-31 15:30:39 +0100548
549 return 0;
550}
551
552static int luton_initialize(struct luton_private *priv)
553{
554 int ret, i;
555
556 /* Initialize switch memories, enable core */
557 ret = luton_switch_init(priv);
558 if (ret)
559 return ret;
560
561 /*
562 * Disable port-to-port by switching
563 * Put front ports in "port isolation modes" - i.e. they can't send
564 * to other ports - via the PGID sorce masks.
565 */
566 for (i = 0; i < MAX_PORT; i++)
567 writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
568
569 /* Flush queues */
570 mscc_flush(priv->regs[QS], luton_regs_qs);
571
572 /* Setup frame ageing - "2 sec" - The unit is 4ns on Luton*/
573 writel(2000000000 / 4,
574 priv->regs[SYS] + SYS_FRM_AGING);
575
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200576 for (i = 0; i < MAX_PORT; i++) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100577 if (i < PORT10)
578 luton_gmii_port_init(priv, i);
579 else
580 if (i == PORT10 || i == PORT11)
581 luton_port_init(priv, i);
582 else
583 luton_ext_port_init(priv, i);
584 }
585
586 luton_cpu_capture_setup(priv);
587
588 return 0;
589}
590
591static int luton_write_hwaddr(struct udevice *dev)
592{
593 struct luton_private *priv = dev_get_priv(dev);
594 struct eth_pdata *pdata = dev_get_platdata(dev);
595
596 mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
597 pdata->enetaddr, PGID_UNICAST);
598
599 writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
600
601 return 0;
602}
603
604static int luton_start(struct udevice *dev)
605{
606 struct luton_private *priv = dev_get_priv(dev);
607 struct eth_pdata *pdata = dev_get_platdata(dev);
608 const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
609 0xff };
610 int ret;
611
612 ret = luton_initialize(priv);
613 if (ret)
614 return ret;
615
616 /* Set MAC address tables entries for CPU redirection */
617 mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
618 mac, PGID_BROADCAST);
619
620 writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
621 priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
622
623 mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
624 pdata->enetaddr, PGID_UNICAST);
625
626 writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
627
628 return 0;
629}
630
631static int luton_send(struct udevice *dev, void *packet, int length)
632{
633 struct luton_private *priv = dev_get_priv(dev);
634 u32 ifh[IFH_LEN];
635 int port = BIT(0); /* use port 0 */
636 u32 *buf = packet;
637
638 ifh[0] = IFH_INJ_BYPASS | port;
639 ifh[1] = (IFH_TAG_TYPE_C << 16);
640
641 return mscc_send(priv->regs[QS], luton_regs_qs,
642 ifh, IFH_LEN, buf, length);
643}
644
645static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
646{
647 struct luton_private *priv = dev_get_priv(dev);
648 u32 *rxbuf = (u32 *)net_rx_packets[0];
649 int byte_cnt = 0;
650
651 byte_cnt = mscc_recv(priv->regs[QS], luton_regs_qs, rxbuf, IFH_LEN,
652 true);
653
654 *packetp = net_rx_packets[0];
655
656 return byte_cnt;
657}
658
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200659static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
660{
661 int i = 0;
662
663 for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i)
664 if (miim[i].miim_base == base && miim[i].miim_size == size)
665 return miim[i].bus;
666
667 return NULL;
668}
669
670static void add_port_entry(struct luton_private *priv, size_t index,
671 size_t phy_addr, struct mii_dev *bus,
672 u8 serdes_index, u8 phy_mode)
673{
674 priv->ports[index].phy_addr = phy_addr;
675 priv->ports[index].bus = bus;
676 priv->ports[index].serdes_index = serdes_index;
677 priv->ports[index].phy_mode = phy_mode;
678}
679
Horatiu Vultura4097192019-01-31 15:30:39 +0100680static int luton_probe(struct udevice *dev)
681{
682 struct luton_private *priv = dev_get_priv(dev);
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200683 int i, ret;
684 struct resource res;
685 fdt32_t faddr;
686 phys_addr_t addr_base;
687 unsigned long addr_size;
688 ofnode eth_node, node, mdio_node;
689 size_t phy_addr;
690 struct mii_dev *bus;
691 struct ofnode_phandle_args phandle;
692 struct phy_device *phy;
Horatiu Vultura4097192019-01-31 15:30:39 +0100693
694 if (!priv)
695 return -EINVAL;
696
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200697 /* Get registers and map them to the private structure */
698 for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
699 priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
700 if (!priv->regs[i]) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100701 debug
702 ("Error can't get regs base addresses for %s\n",
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200703 regs_names[i]);
Horatiu Vultura4097192019-01-31 15:30:39 +0100704 return -ENOMEM;
705 }
706 }
707
708 /* Release reset in the CU-PHY */
709 writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST);
710
711 /* Ports with ext phy don't need to reset clk */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200712 for (i = 0; i < MAX_INT_PORT; i++) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100713 if (i < PORT10)
714 clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK,
715 DEV_GMII_PORT_MODE_CLK_PHY_RST);
716 else
717 clrbits_le32(priv->regs[i] + DEV_PORT_MODE_CLK,
718 DEV_PORT_MODE_CLK_PHY_RST);
719 }
720
721 /* Wait for internal PHY to be ready */
722 if (wait_for_bit_le32(priv->regs[GCB] + GCB_MISC_STAT,
723 GCB_MISC_STAT_PHY_READY, true, 500, false))
724 return -EACCES;
725
Horatiu Vultura4097192019-01-31 15:30:39 +0100726
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200727 /* Initialize miim buses */
728 memset(&miim, 0x0, sizeof(miim) * LUTON_MIIM_BUS_COUNT);
729
730 /* iterate all the ports and find out on which bus they are */
731 i = 0;
732 eth_node = dev_read_first_subnode(dev);
733 for (node = ofnode_first_subnode(eth_node);
734 ofnode_valid(node);
735 node = ofnode_next_subnode(node)) {
736 if (ofnode_read_resource(node, 0, &res))
737 return -ENOMEM;
738 i = res.start;
739
740 ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
741 0, 0, &phandle);
742 if (ret)
743 continue;
744
745 /* Get phy address on mdio bus */
746 if (ofnode_read_resource(phandle.node, 0, &res))
747 return -ENOMEM;
748 phy_addr = res.start;
749
750 /* Get mdio node */
751 mdio_node = ofnode_get_parent(phandle.node);
752
753 if (ofnode_read_resource(mdio_node, 0, &res))
754 return -ENOMEM;
755 faddr = cpu_to_fdt32(res.start);
756
757 addr_base = ofnode_translate_address(mdio_node, &faddr);
758 addr_size = res.end - res.start;
759
760 /* If the bus is new then create a new bus */
761 if (!get_mdiobus(addr_base, addr_size))
762 priv->bus[miim_count] =
763 serval_mdiobus_init(addr_base, addr_size);
764
765 /* Connect mdio bus with the port */
766 bus = get_mdiobus(addr_base, addr_size);
767
768 /* Get serdes info */
769 ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
770 3, 0, &phandle);
771 if (ret)
772 add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
773 else
774 add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
775 phandle.args[2]);
776 }
777
778 for (i = 0; i < MAX_PORT; i++) {
779 if (!priv->ports[i].bus)
780 continue;
781
782 phy = phy_connect(priv->ports[i].bus,
783 priv->ports[i].phy_addr, dev,
784 PHY_INTERFACE_MODE_NONE);
785 if (phy && i >= MAX_INT_PORT)
786 board_phy_config(phy);
Horatiu Vultura4097192019-01-31 15:30:39 +0100787 }
788
789 /*
790 * coma_mode is need on only one phy, because all the other phys
791 * will be affected.
792 */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200793 mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10);
794 mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800);
795 mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0);
Horatiu Vultura4097192019-01-31 15:30:39 +0100796
797 return 0;
798}
799
800static int luton_remove(struct udevice *dev)
801{
802 struct luton_private *priv = dev_get_priv(dev);
803 int i;
804
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200805 for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100806 mdio_unregister(priv->bus[i]);
807 mdio_free(priv->bus[i]);
808 }
809
810 return 0;
811}
812
813static const struct eth_ops luton_ops = {
814 .start = luton_start,
815 .stop = luton_stop,
816 .send = luton_send,
817 .recv = luton_recv,
818 .write_hwaddr = luton_write_hwaddr,
819};
820
821static const struct udevice_id mscc_luton_ids[] = {
822 {.compatible = "mscc,vsc7527-switch", },
823 { /* Sentinel */ }
824};
825
826U_BOOT_DRIVER(luton) = {
827 .name = "luton-switch",
828 .id = UCLASS_ETH,
829 .of_match = mscc_luton_ids,
830 .probe = luton_probe,
831 .remove = luton_remove,
832 .ops = &luton_ops,
833 .priv_auto_alloc_size = sizeof(struct luton_private),
834 .platdata_auto_alloc_size = sizeof(struct eth_pdata),
835};