blob: 1d46d0e5e1e2eae1d6e5fae5b4c6f5b86fc115fc [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);
500 struct eth_pdata *pdata = dev_get_platdata(dev);
501
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);
513 struct eth_pdata *pdata = dev_get_platdata(dev);
514 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;
591 fdt32_t faddr;
592 phys_addr_t addr_base;
593 unsigned long addr_size;
594 ofnode eth_node, node, mdio_node;
595 size_t phy_addr;
596 struct mii_dev *bus;
597 struct ofnode_phandle_args phandle;
598 struct phy_device *phy;
Horatiu Vultura4097192019-01-31 15:30:39 +0100599
600 if (!priv)
601 return -EINVAL;
602
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200603 /* Get registers and map them to the private structure */
604 for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
605 priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
606 if (!priv->regs[i]) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100607 debug
608 ("Error can't get regs base addresses for %s\n",
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200609 regs_names[i]);
Horatiu Vultura4097192019-01-31 15:30:39 +0100610 return -ENOMEM;
611 }
612 }
613
614 /* Release reset in the CU-PHY */
615 writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST);
616
617 /* Ports with ext phy don't need to reset clk */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200618 for (i = 0; i < MAX_INT_PORT; i++) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100619 if (i < PORT10)
620 clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK,
621 DEV_GMII_PORT_MODE_CLK_PHY_RST);
622 else
623 clrbits_le32(priv->regs[i] + DEV_PORT_MODE_CLK,
624 DEV_PORT_MODE_CLK_PHY_RST);
625 }
626
627 /* Wait for internal PHY to be ready */
628 if (wait_for_bit_le32(priv->regs[GCB] + GCB_MISC_STAT,
629 GCB_MISC_STAT_PHY_READY, true, 500, false))
630 return -EACCES;
631
Horatiu Vultura4097192019-01-31 15:30:39 +0100632
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200633 /* Initialize miim buses */
634 memset(&miim, 0x0, sizeof(miim) * LUTON_MIIM_BUS_COUNT);
635
636 /* iterate all the ports and find out on which bus they are */
637 i = 0;
638 eth_node = dev_read_first_subnode(dev);
639 for (node = ofnode_first_subnode(eth_node);
640 ofnode_valid(node);
641 node = ofnode_next_subnode(node)) {
642 if (ofnode_read_resource(node, 0, &res))
643 return -ENOMEM;
644 i = res.start;
645
646 ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
647 0, 0, &phandle);
648 if (ret)
649 continue;
650
651 /* Get phy address on mdio bus */
652 if (ofnode_read_resource(phandle.node, 0, &res))
653 return -ENOMEM;
654 phy_addr = res.start;
655
656 /* Get mdio node */
657 mdio_node = ofnode_get_parent(phandle.node);
658
659 if (ofnode_read_resource(mdio_node, 0, &res))
660 return -ENOMEM;
661 faddr = cpu_to_fdt32(res.start);
662
663 addr_base = ofnode_translate_address(mdio_node, &faddr);
664 addr_size = res.end - res.start;
665
666 /* If the bus is new then create a new bus */
667 if (!get_mdiobus(addr_base, addr_size))
668 priv->bus[miim_count] =
Horatiu Vultur6fbf1612019-06-09 15:27:29 +0200669 mscc_mdiobus_init(miim, &miim_count, addr_base,
670 addr_size);
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200671
672 /* Connect mdio bus with the port */
673 bus = get_mdiobus(addr_base, addr_size);
674
675 /* Get serdes info */
676 ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
677 3, 0, &phandle);
678 if (ret)
679 add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
680 else
681 add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
682 phandle.args[2]);
683 }
684
685 for (i = 0; i < MAX_PORT; i++) {
686 if (!priv->ports[i].bus)
687 continue;
688
689 phy = phy_connect(priv->ports[i].bus,
690 priv->ports[i].phy_addr, dev,
691 PHY_INTERFACE_MODE_NONE);
692 if (phy && i >= MAX_INT_PORT)
693 board_phy_config(phy);
Horatiu Vultura4097192019-01-31 15:30:39 +0100694 }
695
696 /*
697 * coma_mode is need on only one phy, because all the other phys
698 * will be affected.
699 */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200700 mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10);
701 mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800);
702 mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0);
Horatiu Vultura4097192019-01-31 15:30:39 +0100703
704 return 0;
705}
706
707static int luton_remove(struct udevice *dev)
708{
709 struct luton_private *priv = dev_get_priv(dev);
710 int i;
711
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200712 for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100713 mdio_unregister(priv->bus[i]);
714 mdio_free(priv->bus[i]);
715 }
716
717 return 0;
718}
719
720static const struct eth_ops luton_ops = {
721 .start = luton_start,
722 .stop = luton_stop,
723 .send = luton_send,
724 .recv = luton_recv,
725 .write_hwaddr = luton_write_hwaddr,
726};
727
728static const struct udevice_id mscc_luton_ids[] = {
729 {.compatible = "mscc,vsc7527-switch", },
730 { /* Sentinel */ }
731};
732
733U_BOOT_DRIVER(luton) = {
734 .name = "luton-switch",
735 .id = UCLASS_ETH,
736 .of_match = mscc_luton_ids,
737 .probe = luton_probe,
738 .remove = luton_remove,
739 .ops = &luton_ops,
740 .priv_auto_alloc_size = sizeof(struct luton_private),
741 .platdata_auto_alloc_size = sizeof(struct eth_pdata),
742};