blob: 9d24c005c12d2f3496da07d37124caf614252225 [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>
13#include <linux/io.h>
14#include <linux/ioport.h>
15#include <miiphy.h>
16#include <net.h>
17#include <wait_bit.h>
18
Horatiu Vultura4097192019-01-31 15:30:39 +010019#include "mscc_xfer.h"
20#include "mscc_mac_table.h"
Horatiu Vultur6fbf1612019-06-09 15:27:29 +020021#include "mscc_miim.h"
Horatiu Vultur7afd7942019-05-01 13:16:58 +020022
Horatiu Vultura4097192019-01-31 15:30:39 +010023#define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x))
24#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20)
25#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18)
26#define ANA_PORT_CPU_FWD_CFG(x) (0x50 + 0x80 * (x))
27#define ANA_PORT_CPU_FWD_CFG_SRC_COPY_ENA BIT(1)
28#define ANA_PORT_PORT_CFG(x) (0x60 + 0x80 * (x))
29#define ANA_PORT_PORT_CFG_RECV_ENA BIT(5)
30#define ANA_PGID(x) (0x1000 + 4 * (x))
31
32#define SYS_FRM_AGING 0x8300
33
34#define SYS_SYSTEM_RST_CFG 0x81b0
35#define SYS_SYSTEM_RST_MEM_INIT BIT(0)
36#define SYS_SYSTEM_RST_MEM_ENA BIT(1)
37#define SYS_SYSTEM_RST_CORE_ENA BIT(2)
38#define SYS_PORT_MODE(x) (0x81bc + 0x4 * (x))
39#define SYS_PORT_MODE_INCL_INJ_HDR BIT(0)
40#define SYS_SWITCH_PORT_MODE(x) (0x8294 + 0x4 * (x))
41#define SYS_SWITCH_PORT_MODE_PORT_ENA BIT(3)
42#define SYS_EGR_NO_SHARING 0x8378
43#define SYS_SCH_CPU 0x85a0
44
45#define REW_PORT_CFG(x) (0x8 + 0x80 * (x))
46#define REW_PORT_CFG_IFH_INSERT_ENA BIT(7)
47
48#define GCB_DEVCPU_RST_SOFT_CHIP_RST 0x90
49#define GCB_DEVCPU_RST_SOFT_CHIP_RST_SOFT_PHY BIT(1)
50#define GCB_MISC_STAT 0x11c
51#define GCB_MISC_STAT_PHY_READY BIT(3)
52
53#define QS_XTR_MAP(x) (0x10 + 4 * (x))
54#define QS_XTR_MAP_GRP BIT(4)
55#define QS_XTR_MAP_ENA BIT(0)
56
57#define HSIO_PLL5G_CFG_PLL5G_CFG2 0x8
58
59#define HSIO_RCOMP_CFG_CFG0 0x20
60#define HSIO_RCOMP_CFG_CFG0_MODE_SEL(x) ((x) << 8)
61#define HSIO_RCOMP_CFG_CFG0_RUN_CAL BIT(12)
62#define HSIO_RCOMP_STATUS 0x24
63#define HSIO_RCOMP_STATUS_BUSY BIT(12)
64#define HSIO_RCOMP_STATUS_RCOMP_M GENMASK(3, 0)
65#define HSIO_SERDES6G_ANA_CFG_DES_CFG 0x64
66#define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(x) ((x) << 1)
67#define HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(x) ((x) << 5)
68#define HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(x) ((x) << 10)
69#define HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(x) ((x) << 13)
70#define HSIO_SERDES6G_ANA_CFG_IB_CFG 0x68
71#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(x) (x)
72#define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(x) ((x) << 4)
73#define HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(x) ((x) << 7)
74#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(x) ((x) << 9)
75#define HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(x) ((x) << 14)
76#define HSIO_SERDES6G_ANA_CFG_IB_CFG1 0x6c
77#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST BIT(0)
78#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC BIT(2)
79#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC BIT(3)
80#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE BIT(6)
81#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF BIT(7)
82#define HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(x) ((x) << 8)
83#define HSIO_SERDES6G_ANA_CFG_OB_CFG 0x70
84#define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(x) ((x) << 4)
85#define HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H BIT(8)
86#define HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(x) ((x) << 23)
87#define HSIO_SERDES6G_ANA_CFG_OB_CFG_POL BIT(29)
88#define HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE BIT(30)
89#define HSIO_SERDES6G_ANA_CFG_OB_CFG1 0x74
90#define HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(x) (x)
91#define HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(x) ((x) << 6)
92#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG 0x7c
93#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(x) (x)
94#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE BIT(18)
95#define HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST BIT(31)
96#define HSIO_SERDES6G_ANA_CFG_PLL_CFG 0x80
97#define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA BIT(7)
98#define HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8)
99#define HSIO_SERDES6G_ANA_CFG_SER_CFG 0x84
100#define HSIO_SERDES6G_DIG_CFG_MISC_CFG 0x88
101#define HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST BIT(0)
102#define HSIO_MCB_SERDES6G_CFG 0xac
103#define HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT BIT(31)
104#define HSIO_MCB_SERDES6G_CFG_ADDR(x) (x)
105
106#define DEV_GMII_PORT_MODE_CLK 0x0
107#define DEV_GMII_PORT_MODE_CLK_PHY_RST BIT(0)
108#define DEV_GMII_MAC_CFG_MAC_ENA 0xc
109#define DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
110#define DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
111
112#define DEV_PORT_MODE_CLK 0x4
113#define DEV_PORT_MODE_CLK_PHY_RST BIT(2)
114#define DEV_PORT_MODE_CLK_LINK_SPEED_1000 1
115#define DEV_MAC_CFG_MAC_ENA 0x10
116#define DEV_MAC_CFG_MAC_ENA_RX_ENA BIT(4)
117#define DEV_MAC_CFG_MAC_ENA_TX_ENA BIT(0)
118#define DEV_MAC_CFG_MAC_IFG 0x24
119#define DEV_MAC_CFG_MAC_IFG_TX_IFG(x) ((x) << 8)
120#define DEV_MAC_CFG_MAC_IFG_RX_IFG2(x) ((x) << 4)
121#define DEV_MAC_CFG_MAC_IFG_RX_IFG1(x) (x)
122#define DEV_PCS1G_CFG_PCS1G_CFG 0x40
123#define DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA BIT(0)
124#define DEV_PCS1G_CFG_PCS1G_MODE 0x44
125#define DEV_PCS1G_CFG_PCS1G_SD 0x48
126#define DEV_PCS1G_CFG_PCS1G_ANEG 0x4c
127#define DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(x) ((x) << 16)
128
129#define IFH_INJ_BYPASS BIT(31)
130#define IFH_TAG_TYPE_C 0
131#define MAC_VID 1
132#define CPU_PORT 26
133#define INTERNAL_PORT_MSK 0xFFFFFF
134#define IFH_LEN 2
135#define ETH_ALEN 6
136#define PGID_BROADCAST 28
137#define PGID_UNICAST 29
138#define PGID_SRC 80
139
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200140static const char * const regs_names[] = {
141 "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
142 "port8", "port9", "port10", "port11", "port12", "port13", "port14",
143 "port15", "port16", "port17", "port18", "port19", "port20", "port21",
144 "port22", "port23",
145 "sys", "ana", "rew", "gcb", "qs", "hsio",
146};
147
148#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
149#define MAX_PORT 24
150
151enum luton_ctrl_regs {
152 SYS = MAX_PORT,
Horatiu Vultura4097192019-01-31 15:30:39 +0100153 ANA,
154 REW,
155 GCB,
156 QS,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200157 HSIO
Horatiu Vultura4097192019-01-31 15:30:39 +0100158};
159
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200160#define MIN_INT_PORT 0
161#define PORT10 10
162#define PORT11 11
163#define MAX_INT_PORT 12
164#define MIN_EXT_PORT MAX_INT_PORT
165#define MAX_EXT_PORT MAX_PORT
Horatiu Vultura4097192019-01-31 15:30:39 +0100166
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200167#define LUTON_MIIM_BUS_COUNT 2
Horatiu Vultura4097192019-01-31 15:30:39 +0100168
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200169struct luton_phy_port_t {
170 size_t phy_addr;
171 struct mii_dev *bus;
172 u8 serdes_index;
173 u8 phy_mode;
Horatiu Vultura4097192019-01-31 15:30:39 +0100174};
175
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200176struct luton_private {
177 void __iomem *regs[REGS_NAMES_COUNT];
178 struct mii_dev *bus[LUTON_MIIM_BUS_COUNT];
179 struct luton_phy_port_t ports[MAX_PORT];
Horatiu Vultura4097192019-01-31 15:30:39 +0100180};
181
Horatiu Vultura4097192019-01-31 15:30:39 +0100182static const unsigned long luton_regs_qs[] = {
183 [MSCC_QS_XTR_RD] = 0x18,
184 [MSCC_QS_XTR_FLUSH] = 0x28,
185 [MSCC_QS_XTR_DATA_PRESENT] = 0x2c,
186 [MSCC_QS_INJ_WR] = 0x3c,
187 [MSCC_QS_INJ_CTRL] = 0x44,
188};
189
190static const unsigned long luton_regs_ana_table[] = {
191 [MSCC_ANA_TABLES_MACHDATA] = 0x11b0,
192 [MSCC_ANA_TABLES_MACLDATA] = 0x11b4,
193 [MSCC_ANA_TABLES_MACACCESS] = 0x11b8,
194};
195
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200196static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT];
197static int miim_count = -1;
Horatiu Vultura4097192019-01-31 15:30:39 +0100198
Horatiu Vultura4097192019-01-31 15:30:39 +0100199static void luton_stop(struct udevice *dev)
200{
201 struct luton_private *priv = dev_get_priv(dev);
202
203 /*
204 * Switch core only reset affects VCORE-III bus and MIPS frequency
205 * and thereby also the DDR SDRAM controller. The workaround is to
206 * not to redirect any trafic to the CPU after the data transfer.
207 */
208 writel(GENMASK(9, 2), priv->regs[SYS] + SYS_SCH_CPU);
209}
210
211static void luton_cpu_capture_setup(struct luton_private *priv)
212{
213 int i;
214
215 /* map the 8 CPU extraction queues to CPU port 26 */
216 writel(0x0, priv->regs[SYS] + SYS_SCH_CPU);
217
218 for (i = 0; i <= 1; i++) {
219 /*
220 * One to one mapping from CPU Queue number to Group extraction
221 * number
222 */
223 writel(QS_XTR_MAP_ENA | (QS_XTR_MAP_GRP * i),
224 priv->regs[QS] + QS_XTR_MAP(i));
225
226 /* Enable IFH insertion/parsing on CPU ports */
227 setbits_le32(priv->regs[REW] + REW_PORT_CFG(CPU_PORT + i),
228 REW_PORT_CFG_IFH_INSERT_ENA);
229
230 /* Enable IFH parsing on CPU port 0 and 1 */
231 setbits_le32(priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i),
232 SYS_PORT_MODE_INCL_INJ_HDR);
233 }
234
235 /* Make VLAN aware for CPU traffic */
236 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
237 ANA_PORT_VLAN_CFG_POP_CNT(1) |
238 MAC_VID,
239 priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
240
241 /* Disable learning (only RECV_ENA must be set) */
242 writel(ANA_PORT_PORT_CFG_RECV_ENA,
243 priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
244
245 /* Enable switching to/from cpu port */
246 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(CPU_PORT),
247 SYS_SWITCH_PORT_MODE_PORT_ENA);
248
249 setbits_le32(priv->regs[SYS] + SYS_EGR_NO_SHARING, BIT(CPU_PORT));
250}
251
252static void luton_gmii_port_init(struct luton_private *priv, int port)
253{
254 void __iomem *regs = priv->regs[port];
255
256 writel(0, regs + DEV_GMII_PORT_MODE_CLK);
257
258 /* Enable MAC RX and TX */
259 writel(DEV_GMII_MAC_CFG_MAC_ENA_RX_ENA |
260 DEV_GMII_MAC_CFG_MAC_ENA_TX_ENA,
261 regs + DEV_GMII_MAC_CFG_MAC_ENA);
262
263 /* Make VLAN aware for CPU traffic */
264 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
265 ANA_PORT_VLAN_CFG_POP_CNT(1) |
266 MAC_VID,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200267 priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
Horatiu Vultura4097192019-01-31 15:30:39 +0100268
269 /* Enable switching to/from port */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200270 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
Horatiu Vultura4097192019-01-31 15:30:39 +0100271 SYS_SWITCH_PORT_MODE_PORT_ENA);
272}
273
274static void luton_port_init(struct luton_private *priv, int port)
275{
276 void __iomem *regs = priv->regs[port];
277
278 writel(0, regs + DEV_PORT_MODE_CLK);
279
280 /* Enable MAC RX and TX */
281 writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
282 DEV_MAC_CFG_MAC_ENA_TX_ENA,
283 regs + DEV_MAC_CFG_MAC_ENA);
284
285 /* Make VLAN aware for CPU traffic */
286 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
287 ANA_PORT_VLAN_CFG_POP_CNT(1) |
288 MAC_VID,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200289 priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
Horatiu Vultura4097192019-01-31 15:30:39 +0100290
291 /* Enable switching to/from port */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200292 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
Horatiu Vultura4097192019-01-31 15:30:39 +0100293 SYS_SWITCH_PORT_MODE_PORT_ENA);
294}
295
296static void luton_ext_port_init(struct luton_private *priv, int port)
297{
298 void __iomem *regs = priv->regs[port];
299
300 /* Enable PCS */
301 writel(DEV_PCS1G_CFG_PCS1G_CFG_PCS_ENA,
302 regs + DEV_PCS1G_CFG_PCS1G_CFG);
303
304 /* Disable Signal Detect */
305 writel(0, regs + DEV_PCS1G_CFG_PCS1G_SD);
306
307 /* Enable MAC RX and TX */
308 writel(DEV_MAC_CFG_MAC_ENA_RX_ENA |
309 DEV_MAC_CFG_MAC_ENA_TX_ENA,
310 regs + DEV_MAC_CFG_MAC_ENA);
311
312 /* Clear sgmii_mode_ena */
313 writel(0, regs + DEV_PCS1G_CFG_PCS1G_MODE);
314
315 /*
316 * Clear sw_resolve_ena(bit 0) and set adv_ability to
317 * something meaningful just in case
318 */
319 writel(DEV_PCS1G_CFG_PCS1G_ANEG_ADV_ABILITY(0x20),
320 regs + DEV_PCS1G_CFG_PCS1G_ANEG);
321
322 /* Set MAC IFG Gaps */
323 writel(DEV_MAC_CFG_MAC_IFG_TX_IFG(7) |
324 DEV_MAC_CFG_MAC_IFG_RX_IFG1(1) |
325 DEV_MAC_CFG_MAC_IFG_RX_IFG2(5),
326 regs + DEV_MAC_CFG_MAC_IFG);
327
328 /* Set link speed and release all resets */
329 writel(DEV_PORT_MODE_CLK_LINK_SPEED_1000,
330 regs + DEV_PORT_MODE_CLK);
331
332 /* Make VLAN aware for CPU traffic */
333 writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
334 ANA_PORT_VLAN_CFG_POP_CNT(1) |
335 MAC_VID,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200336 priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
Horatiu Vultura4097192019-01-31 15:30:39 +0100337
338 /* Enable switching to/from port */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200339 setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
Horatiu Vultura4097192019-01-31 15:30:39 +0100340 SYS_SWITCH_PORT_MODE_PORT_ENA);
341}
342
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200343static void serdes6g_write(void __iomem *base, u32 addr)
Horatiu Vultura4097192019-01-31 15:30:39 +0100344{
345 u32 data;
346
347 writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
348 HSIO_MCB_SERDES6G_CFG_ADDR(addr),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200349 base + HSIO_MCB_SERDES6G_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100350
351 do {
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200352 data = readl(base + HSIO_MCB_SERDES6G_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100353 } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
Horatiu Vultura4097192019-01-31 15:30:39 +0100354}
355
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200356static void serdes6g_setup(void __iomem *base, uint32_t addr,
357 phy_interface_t interface)
Horatiu Vultura4097192019-01-31 15:30:39 +0100358{
359 writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
360 HSIO_RCOMP_CFG_CFG0_RUN_CAL,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200361 base + HSIO_RCOMP_CFG_CFG0);
Horatiu Vultura4097192019-01-31 15:30:39 +0100362
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200363 while (readl(base + HSIO_RCOMP_STATUS) &
Horatiu Vultura4097192019-01-31 15:30:39 +0100364 HSIO_RCOMP_STATUS_BUSY)
365 ;
366
367 writel(HSIO_SERDES6G_ANA_CFG_OB_CFG_SR(0xb) |
368 HSIO_SERDES6G_ANA_CFG_OB_CFG_SR_H |
369 HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
370 HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
371 HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200372 base + HSIO_SERDES6G_ANA_CFG_OB_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100373 writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
374 HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200375 base + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
Horatiu Vultura4097192019-01-31 15:30:39 +0100376 writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
377 HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
378 HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
379 HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
380 HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200381 base + HSIO_SERDES6G_ANA_CFG_IB_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100382 writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
383 HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
384 HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
385 HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
386 HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
387 HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200388 base + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
Horatiu Vultura4097192019-01-31 15:30:39 +0100389 writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
390 HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
391 HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
392 HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200393 base + HSIO_SERDES6G_ANA_CFG_DES_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100394 writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
395 HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200396 base + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100397 writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
398 HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200399 base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
Horatiu Vultura4097192019-01-31 15:30:39 +0100400 /*
401 * There are 4 serdes6g, configure all except serdes6g0, therefore
402 * the address is b1110
403 */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200404 serdes6g_write(base, addr);
Horatiu Vultura4097192019-01-31 15:30:39 +0100405
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200406 writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
Horatiu Vultura4097192019-01-31 15:30:39 +0100407 HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200408 base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
409 serdes6g_write(base, addr);
Horatiu Vultura4097192019-01-31 15:30:39 +0100410
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200411 clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
Horatiu Vultura4097192019-01-31 15:30:39 +0100412 HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
413 writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200414 base + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
415 serdes6g_write(base, addr);
Horatiu Vultura4097192019-01-31 15:30:39 +0100416}
417
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200418static void serdes_setup(struct luton_private *priv)
419{
420 size_t mask;
421 int i = 0;
422
423 for (i = 0; i < MAX_PORT; ++i) {
424 if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
425 continue;
426
427 mask = BIT(priv->ports[i].serdes_index);
428 serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode);
429 }
430}
431
Horatiu Vultura4097192019-01-31 15:30:39 +0100432static int luton_switch_init(struct luton_private *priv)
433{
434 setbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
435 clrbits_le32(priv->regs[HSIO] + HSIO_PLL5G_CFG_PLL5G_CFG2, BIT(1));
436
437 /* Reset switch & memories */
438 writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
439 priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
440
441 /* Wait to complete */
442 if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
443 SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
444 printf("Timeout in memory reset\n");
445 }
446
447 /* Enable switch core */
448 setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
449 SYS_SYSTEM_RST_CORE_ENA);
450
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200451 /* Setup the Serdes macros */
452 serdes_setup(priv);
Horatiu Vultura4097192019-01-31 15:30:39 +0100453
454 return 0;
455}
456
457static int luton_initialize(struct luton_private *priv)
458{
459 int ret, i;
460
461 /* Initialize switch memories, enable core */
462 ret = luton_switch_init(priv);
463 if (ret)
464 return ret;
465
466 /*
467 * Disable port-to-port by switching
468 * Put front ports in "port isolation modes" - i.e. they can't send
469 * to other ports - via the PGID sorce masks.
470 */
471 for (i = 0; i < MAX_PORT; i++)
472 writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
473
474 /* Flush queues */
475 mscc_flush(priv->regs[QS], luton_regs_qs);
476
477 /* Setup frame ageing - "2 sec" - The unit is 4ns on Luton*/
478 writel(2000000000 / 4,
479 priv->regs[SYS] + SYS_FRM_AGING);
480
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200481 for (i = 0; i < MAX_PORT; i++) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100482 if (i < PORT10)
483 luton_gmii_port_init(priv, i);
484 else
485 if (i == PORT10 || i == PORT11)
486 luton_port_init(priv, i);
487 else
488 luton_ext_port_init(priv, i);
489 }
490
491 luton_cpu_capture_setup(priv);
492
493 return 0;
494}
495
496static int luton_write_hwaddr(struct udevice *dev)
497{
498 struct luton_private *priv = dev_get_priv(dev);
499 struct eth_pdata *pdata = dev_get_platdata(dev);
500
501 mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
502 pdata->enetaddr, PGID_UNICAST);
503
504 writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
505
506 return 0;
507}
508
509static int luton_start(struct udevice *dev)
510{
511 struct luton_private *priv = dev_get_priv(dev);
512 struct eth_pdata *pdata = dev_get_platdata(dev);
513 const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
514 0xff };
515 int ret;
516
517 ret = luton_initialize(priv);
518 if (ret)
519 return ret;
520
521 /* Set MAC address tables entries for CPU redirection */
522 mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
523 mac, PGID_BROADCAST);
524
525 writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
526 priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
527
528 mscc_mac_table_add(priv->regs[ANA], luton_regs_ana_table,
529 pdata->enetaddr, PGID_UNICAST);
530
531 writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
532
533 return 0;
534}
535
536static int luton_send(struct udevice *dev, void *packet, int length)
537{
538 struct luton_private *priv = dev_get_priv(dev);
539 u32 ifh[IFH_LEN];
540 int port = BIT(0); /* use port 0 */
541 u32 *buf = packet;
542
543 ifh[0] = IFH_INJ_BYPASS | port;
544 ifh[1] = (IFH_TAG_TYPE_C << 16);
545
546 return mscc_send(priv->regs[QS], luton_regs_qs,
547 ifh, IFH_LEN, buf, length);
548}
549
550static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
551{
552 struct luton_private *priv = dev_get_priv(dev);
553 u32 *rxbuf = (u32 *)net_rx_packets[0];
554 int byte_cnt = 0;
555
556 byte_cnt = mscc_recv(priv->regs[QS], luton_regs_qs, rxbuf, IFH_LEN,
557 true);
558
559 *packetp = net_rx_packets[0];
560
561 return byte_cnt;
562}
563
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200564static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
565{
566 int i = 0;
567
568 for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i)
569 if (miim[i].miim_base == base && miim[i].miim_size == size)
570 return miim[i].bus;
571
572 return NULL;
573}
574
575static void add_port_entry(struct luton_private *priv, size_t index,
576 size_t phy_addr, struct mii_dev *bus,
577 u8 serdes_index, u8 phy_mode)
578{
579 priv->ports[index].phy_addr = phy_addr;
580 priv->ports[index].bus = bus;
581 priv->ports[index].serdes_index = serdes_index;
582 priv->ports[index].phy_mode = phy_mode;
583}
584
Horatiu Vultura4097192019-01-31 15:30:39 +0100585static int luton_probe(struct udevice *dev)
586{
587 struct luton_private *priv = dev_get_priv(dev);
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200588 int i, ret;
589 struct resource res;
590 fdt32_t faddr;
591 phys_addr_t addr_base;
592 unsigned long addr_size;
593 ofnode eth_node, node, mdio_node;
594 size_t phy_addr;
595 struct mii_dev *bus;
596 struct ofnode_phandle_args phandle;
597 struct phy_device *phy;
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;
660 faddr = cpu_to_fdt32(res.start);
661
662 addr_base = ofnode_translate_address(mdio_node, &faddr);
663 addr_size = res.end - res.start;
664
665 /* If the bus is new then create a new bus */
666 if (!get_mdiobus(addr_base, addr_size))
667 priv->bus[miim_count] =
Horatiu Vultur6fbf1612019-06-09 15:27:29 +0200668 mscc_mdiobus_init(miim, &miim_count, addr_base,
669 addr_size);
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200670
671 /* Connect mdio bus with the port */
672 bus = get_mdiobus(addr_base, addr_size);
673
674 /* Get serdes info */
675 ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
676 3, 0, &phandle);
677 if (ret)
678 add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
679 else
680 add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
681 phandle.args[2]);
682 }
683
684 for (i = 0; i < MAX_PORT; i++) {
685 if (!priv->ports[i].bus)
686 continue;
687
688 phy = phy_connect(priv->ports[i].bus,
689 priv->ports[i].phy_addr, dev,
690 PHY_INTERFACE_MODE_NONE);
691 if (phy && i >= MAX_INT_PORT)
692 board_phy_config(phy);
Horatiu Vultura4097192019-01-31 15:30:39 +0100693 }
694
695 /*
696 * coma_mode is need on only one phy, because all the other phys
697 * will be affected.
698 */
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200699 mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10);
700 mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800);
701 mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0);
Horatiu Vultura4097192019-01-31 15:30:39 +0100702
703 return 0;
704}
705
706static int luton_remove(struct udevice *dev)
707{
708 struct luton_private *priv = dev_get_priv(dev);
709 int i;
710
Horatiu Vultur7afd7942019-05-01 13:16:58 +0200711 for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) {
Horatiu Vultura4097192019-01-31 15:30:39 +0100712 mdio_unregister(priv->bus[i]);
713 mdio_free(priv->bus[i]);
714 }
715
716 return 0;
717}
718
719static const struct eth_ops luton_ops = {
720 .start = luton_start,
721 .stop = luton_stop,
722 .send = luton_send,
723 .recv = luton_recv,
724 .write_hwaddr = luton_write_hwaddr,
725};
726
727static const struct udevice_id mscc_luton_ids[] = {
728 {.compatible = "mscc,vsc7527-switch", },
729 { /* Sentinel */ }
730};
731
732U_BOOT_DRIVER(luton) = {
733 .name = "luton-switch",
734 .id = UCLASS_ETH,
735 .of_match = mscc_luton_ids,
736 .probe = luton_probe,
737 .remove = luton_remove,
738 .ops = &luton_ops,
739 .priv_auto_alloc_size = sizeof(struct luton_private),
740 .platdata_auto_alloc_size = sizeof(struct eth_pdata),
741};