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