1*3cfa11baSSteen Hegelund /* SPDX-License-Identifier: GPL-2.0+ */
2*3cfa11baSSteen Hegelund /* Microchip Sparx5 Switch driver
3*3cfa11baSSteen Hegelund  *
4*3cfa11baSSteen Hegelund  * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
5*3cfa11baSSteen Hegelund  */
6*3cfa11baSSteen Hegelund 
7*3cfa11baSSteen Hegelund #ifndef __SPARX5_MAIN_H__
8*3cfa11baSSteen Hegelund #define __SPARX5_MAIN_H__
9*3cfa11baSSteen Hegelund 
10*3cfa11baSSteen Hegelund #include <linux/types.h>
11*3cfa11baSSteen Hegelund #include <linux/phy/phy.h>
12*3cfa11baSSteen Hegelund #include <linux/netdevice.h>
13*3cfa11baSSteen Hegelund #include <linux/phy.h>
14*3cfa11baSSteen Hegelund #include <linux/if_vlan.h>
15*3cfa11baSSteen Hegelund #include <linux/bitmap.h>
16*3cfa11baSSteen Hegelund #include <linux/phylink.h>
17*3cfa11baSSteen Hegelund 
18*3cfa11baSSteen Hegelund /* Target chip type */
19*3cfa11baSSteen Hegelund enum spx5_target_chiptype {
20*3cfa11baSSteen Hegelund 	SPX5_TARGET_CT_7546    = 0x7546,  /* SparX-5-64  Enterprise */
21*3cfa11baSSteen Hegelund 	SPX5_TARGET_CT_7549    = 0x7549,  /* SparX-5-90  Enterprise */
22*3cfa11baSSteen Hegelund 	SPX5_TARGET_CT_7552    = 0x7552,  /* SparX-5-128 Enterprise */
23*3cfa11baSSteen Hegelund 	SPX5_TARGET_CT_7556    = 0x7556,  /* SparX-5-160 Enterprise */
24*3cfa11baSSteen Hegelund 	SPX5_TARGET_CT_7558    = 0x7558,  /* SparX-5-200 Enterprise */
25*3cfa11baSSteen Hegelund 	SPX5_TARGET_CT_7546TSN = 0x47546, /* SparX-5-64i Industrial */
26*3cfa11baSSteen Hegelund 	SPX5_TARGET_CT_7549TSN = 0x47549, /* SparX-5-90i Industrial */
27*3cfa11baSSteen Hegelund 	SPX5_TARGET_CT_7552TSN = 0x47552, /* SparX-5-128i Industrial */
28*3cfa11baSSteen Hegelund 	SPX5_TARGET_CT_7556TSN = 0x47556, /* SparX-5-160i Industrial */
29*3cfa11baSSteen Hegelund 	SPX5_TARGET_CT_7558TSN = 0x47558, /* SparX-5-200i Industrial */
30*3cfa11baSSteen Hegelund };
31*3cfa11baSSteen Hegelund 
32*3cfa11baSSteen Hegelund enum sparx5_port_max_tags {
33*3cfa11baSSteen Hegelund 	SPX5_PORT_MAX_TAGS_NONE,  /* No extra tags allowed */
34*3cfa11baSSteen Hegelund 	SPX5_PORT_MAX_TAGS_ONE,   /* Single tag allowed */
35*3cfa11baSSteen Hegelund 	SPX5_PORT_MAX_TAGS_TWO    /* Single and double tag allowed */
36*3cfa11baSSteen Hegelund };
37*3cfa11baSSteen Hegelund 
38*3cfa11baSSteen Hegelund enum sparx5_vlan_port_type {
39*3cfa11baSSteen Hegelund 	SPX5_VLAN_PORT_TYPE_UNAWARE, /* VLAN unaware port */
40*3cfa11baSSteen Hegelund 	SPX5_VLAN_PORT_TYPE_C,       /* C-port */
41*3cfa11baSSteen Hegelund 	SPX5_VLAN_PORT_TYPE_S,       /* S-port */
42*3cfa11baSSteen Hegelund 	SPX5_VLAN_PORT_TYPE_S_CUSTOM /* S-port using custom type */
43*3cfa11baSSteen Hegelund };
44*3cfa11baSSteen Hegelund 
45*3cfa11baSSteen Hegelund #define SPX5_PORTS             65
46*3cfa11baSSteen Hegelund #define SPX5_PORT_CPU          (SPX5_PORTS)  /* Next port is CPU port */
47*3cfa11baSSteen Hegelund #define SPX5_PORT_CPU_0        (SPX5_PORT_CPU + 0) /* CPU Port 65 */
48*3cfa11baSSteen Hegelund #define SPX5_PORT_CPU_1        (SPX5_PORT_CPU + 1) /* CPU Port 66 */
49*3cfa11baSSteen Hegelund #define SPX5_PORT_VD0          (SPX5_PORT_CPU + 2) /* VD0/Port 67 used for IPMC */
50*3cfa11baSSteen Hegelund #define SPX5_PORT_VD1          (SPX5_PORT_CPU + 3) /* VD1/Port 68 used for AFI/OAM */
51*3cfa11baSSteen Hegelund #define SPX5_PORT_VD2          (SPX5_PORT_CPU + 4) /* VD2/Port 69 used for IPinIP*/
52*3cfa11baSSteen Hegelund #define SPX5_PORTS_ALL         (SPX5_PORT_CPU + 5) /* Total number of ports */
53*3cfa11baSSteen Hegelund 
54*3cfa11baSSteen Hegelund #define PGID_BASE              SPX5_PORTS /* Starts after port PGIDs */
55*3cfa11baSSteen Hegelund #define PGID_UC_FLOOD          (PGID_BASE + 0)
56*3cfa11baSSteen Hegelund #define PGID_MC_FLOOD          (PGID_BASE + 1)
57*3cfa11baSSteen Hegelund #define PGID_IPV4_MC_DATA      (PGID_BASE + 2)
58*3cfa11baSSteen Hegelund #define PGID_IPV4_MC_CTRL      (PGID_BASE + 3)
59*3cfa11baSSteen Hegelund #define PGID_IPV6_MC_DATA      (PGID_BASE + 4)
60*3cfa11baSSteen Hegelund #define PGID_IPV6_MC_CTRL      (PGID_BASE + 5)
61*3cfa11baSSteen Hegelund #define PGID_BCAST	       (PGID_BASE + 6)
62*3cfa11baSSteen Hegelund #define PGID_CPU	       (PGID_BASE + 7)
63*3cfa11baSSteen Hegelund 
64*3cfa11baSSteen Hegelund #define IFH_LEN                9 /* 36 bytes */
65*3cfa11baSSteen Hegelund #define NULL_VID               0
66*3cfa11baSSteen Hegelund #define SPX5_MACT_PULL_DELAY   (2 * HZ)
67*3cfa11baSSteen Hegelund #define SPX5_STATS_CHECK_DELAY (1 * HZ)
68*3cfa11baSSteen Hegelund #define SPX5_PRIOS             8     /* Number of priority queues */
69*3cfa11baSSteen Hegelund #define SPX5_BUFFER_CELL_SZ    184   /* Cell size  */
70*3cfa11baSSteen Hegelund #define SPX5_BUFFER_MEMORY     4194280 /* 22795 words * 184 bytes */
71*3cfa11baSSteen Hegelund 
72*3cfa11baSSteen Hegelund struct sparx5;
73*3cfa11baSSteen Hegelund 
74*3cfa11baSSteen Hegelund struct sparx5_port_config {
75*3cfa11baSSteen Hegelund 	phy_interface_t portmode;
76*3cfa11baSSteen Hegelund 	u32 bandwidth;
77*3cfa11baSSteen Hegelund 	int speed;
78*3cfa11baSSteen Hegelund 	int duplex;
79*3cfa11baSSteen Hegelund 	enum phy_media media;
80*3cfa11baSSteen Hegelund 	bool inband;
81*3cfa11baSSteen Hegelund 	bool power_down;
82*3cfa11baSSteen Hegelund 	bool autoneg;
83*3cfa11baSSteen Hegelund 	bool serdes_reset;
84*3cfa11baSSteen Hegelund 	u32 pause;
85*3cfa11baSSteen Hegelund 	u32 pause_adv;
86*3cfa11baSSteen Hegelund 	phy_interface_t phy_mode;
87*3cfa11baSSteen Hegelund 	u32 sd_sgpio;
88*3cfa11baSSteen Hegelund };
89*3cfa11baSSteen Hegelund 
90*3cfa11baSSteen Hegelund struct sparx5_port {
91*3cfa11baSSteen Hegelund 	struct net_device *ndev;
92*3cfa11baSSteen Hegelund 	struct sparx5 *sparx5;
93*3cfa11baSSteen Hegelund 	struct device_node *of_node;
94*3cfa11baSSteen Hegelund 	struct phy *serdes;
95*3cfa11baSSteen Hegelund 	struct sparx5_port_config conf;
96*3cfa11baSSteen Hegelund 	u16 portno;
97*3cfa11baSSteen Hegelund 	/* Ingress default VLAN (pvid) */
98*3cfa11baSSteen Hegelund 	u16 pvid;
99*3cfa11baSSteen Hegelund 	/* Egress default VLAN (vid) */
100*3cfa11baSSteen Hegelund 	u16 vid;
101*3cfa11baSSteen Hegelund 	bool signd_internal;
102*3cfa11baSSteen Hegelund 	bool signd_active_high;
103*3cfa11baSSteen Hegelund 	bool signd_enable;
104*3cfa11baSSteen Hegelund 	bool flow_control;
105*3cfa11baSSteen Hegelund 	enum sparx5_port_max_tags max_vlan_tags;
106*3cfa11baSSteen Hegelund 	enum sparx5_vlan_port_type vlan_type;
107*3cfa11baSSteen Hegelund 	u32 custom_etype;
108*3cfa11baSSteen Hegelund 	u32 ifh[IFH_LEN];
109*3cfa11baSSteen Hegelund 	bool vlan_aware;
110*3cfa11baSSteen Hegelund };
111*3cfa11baSSteen Hegelund 
112*3cfa11baSSteen Hegelund enum sparx5_core_clockfreq {
113*3cfa11baSSteen Hegelund 	SPX5_CORE_CLOCK_DEFAULT,  /* Defaults to the highest supported frequency */
114*3cfa11baSSteen Hegelund 	SPX5_CORE_CLOCK_250MHZ,   /* 250MHZ core clock frequency */
115*3cfa11baSSteen Hegelund 	SPX5_CORE_CLOCK_500MHZ,   /* 500MHZ core clock frequency */
116*3cfa11baSSteen Hegelund 	SPX5_CORE_CLOCK_625MHZ,   /* 625MHZ core clock frequency */
117*3cfa11baSSteen Hegelund };
118*3cfa11baSSteen Hegelund 
119*3cfa11baSSteen Hegelund struct sparx5 {
120*3cfa11baSSteen Hegelund 	struct platform_device *pdev;
121*3cfa11baSSteen Hegelund 	struct device *dev;
122*3cfa11baSSteen Hegelund 	u32 chip_id;
123*3cfa11baSSteen Hegelund 	enum spx5_target_chiptype target_ct;
124*3cfa11baSSteen Hegelund 	void __iomem *regs[NUM_TARGETS];
125*3cfa11baSSteen Hegelund 	int port_count;
126*3cfa11baSSteen Hegelund 	struct mutex lock; /* MAC reg lock */
127*3cfa11baSSteen Hegelund 	/* port structures are in net device */
128*3cfa11baSSteen Hegelund 	struct sparx5_port *ports[SPX5_PORTS];
129*3cfa11baSSteen Hegelund 	enum sparx5_core_clockfreq coreclock;
130*3cfa11baSSteen Hegelund 	u8 base_mac[ETH_ALEN];
131*3cfa11baSSteen Hegelund 	/* Board specifics */
132*3cfa11baSSteen Hegelund 	bool sd_sgpio_remapping;
133*3cfa11baSSteen Hegelund };
134*3cfa11baSSteen Hegelund 
135*3cfa11baSSteen Hegelund /* Clock period in picoseconds */
136*3cfa11baSSteen Hegelund static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock)
137*3cfa11baSSteen Hegelund {
138*3cfa11baSSteen Hegelund 	switch (cclock) {
139*3cfa11baSSteen Hegelund 	case SPX5_CORE_CLOCK_250MHZ:
140*3cfa11baSSteen Hegelund 		return 4000;
141*3cfa11baSSteen Hegelund 	case SPX5_CORE_CLOCK_500MHZ:
142*3cfa11baSSteen Hegelund 		return 2000;
143*3cfa11baSSteen Hegelund 	case SPX5_CORE_CLOCK_625MHZ:
144*3cfa11baSSteen Hegelund 	default:
145*3cfa11baSSteen Hegelund 		return 1600;
146*3cfa11baSSteen Hegelund 	}
147*3cfa11baSSteen Hegelund }
148*3cfa11baSSteen Hegelund 
149*3cfa11baSSteen Hegelund /* Calculate raw offset */
150*3cfa11baSSteen Hegelund static inline __pure int spx5_offset(int id, int tinst, int tcnt,
151*3cfa11baSSteen Hegelund 				     int gbase, int ginst,
152*3cfa11baSSteen Hegelund 				     int gcnt, int gwidth,
153*3cfa11baSSteen Hegelund 				     int raddr, int rinst,
154*3cfa11baSSteen Hegelund 				     int rcnt, int rwidth)
155*3cfa11baSSteen Hegelund {
156*3cfa11baSSteen Hegelund 	WARN_ON((tinst) >= tcnt);
157*3cfa11baSSteen Hegelund 	WARN_ON((ginst) >= gcnt);
158*3cfa11baSSteen Hegelund 	WARN_ON((rinst) >= rcnt);
159*3cfa11baSSteen Hegelund 	return gbase + ((ginst) * gwidth) +
160*3cfa11baSSteen Hegelund 		raddr + ((rinst) * rwidth);
161*3cfa11baSSteen Hegelund }
162*3cfa11baSSteen Hegelund 
163*3cfa11baSSteen Hegelund /* Read, Write and modify registers content.
164*3cfa11baSSteen Hegelund  * The register definition macros start at the id
165*3cfa11baSSteen Hegelund  */
166*3cfa11baSSteen Hegelund static inline void __iomem *spx5_addr(void __iomem *base[],
167*3cfa11baSSteen Hegelund 				      int id, int tinst, int tcnt,
168*3cfa11baSSteen Hegelund 				      int gbase, int ginst,
169*3cfa11baSSteen Hegelund 				      int gcnt, int gwidth,
170*3cfa11baSSteen Hegelund 				      int raddr, int rinst,
171*3cfa11baSSteen Hegelund 				      int rcnt, int rwidth)
172*3cfa11baSSteen Hegelund {
173*3cfa11baSSteen Hegelund 	WARN_ON((tinst) >= tcnt);
174*3cfa11baSSteen Hegelund 	WARN_ON((ginst) >= gcnt);
175*3cfa11baSSteen Hegelund 	WARN_ON((rinst) >= rcnt);
176*3cfa11baSSteen Hegelund 	return base[id + (tinst)] +
177*3cfa11baSSteen Hegelund 		gbase + ((ginst) * gwidth) +
178*3cfa11baSSteen Hegelund 		raddr + ((rinst) * rwidth);
179*3cfa11baSSteen Hegelund }
180*3cfa11baSSteen Hegelund 
181*3cfa11baSSteen Hegelund static inline void __iomem *spx5_inst_addr(void __iomem *base,
182*3cfa11baSSteen Hegelund 					   int gbase, int ginst,
183*3cfa11baSSteen Hegelund 					   int gcnt, int gwidth,
184*3cfa11baSSteen Hegelund 					   int raddr, int rinst,
185*3cfa11baSSteen Hegelund 					   int rcnt, int rwidth)
186*3cfa11baSSteen Hegelund {
187*3cfa11baSSteen Hegelund 	WARN_ON((ginst) >= gcnt);
188*3cfa11baSSteen Hegelund 	WARN_ON((rinst) >= rcnt);
189*3cfa11baSSteen Hegelund 	return base +
190*3cfa11baSSteen Hegelund 		gbase + ((ginst) * gwidth) +
191*3cfa11baSSteen Hegelund 		raddr + ((rinst) * rwidth);
192*3cfa11baSSteen Hegelund }
193*3cfa11baSSteen Hegelund 
194*3cfa11baSSteen Hegelund static inline u32 spx5_rd(struct sparx5 *sparx5, int id, int tinst, int tcnt,
195*3cfa11baSSteen Hegelund 			  int gbase, int ginst, int gcnt, int gwidth,
196*3cfa11baSSteen Hegelund 			  int raddr, int rinst, int rcnt, int rwidth)
197*3cfa11baSSteen Hegelund {
198*3cfa11baSSteen Hegelund 	return readl(spx5_addr(sparx5->regs, id, tinst, tcnt, gbase, ginst,
199*3cfa11baSSteen Hegelund 			       gcnt, gwidth, raddr, rinst, rcnt, rwidth));
200*3cfa11baSSteen Hegelund }
201*3cfa11baSSteen Hegelund 
202*3cfa11baSSteen Hegelund static inline u32 spx5_inst_rd(void __iomem *iomem, int id, int tinst, int tcnt,
203*3cfa11baSSteen Hegelund 			       int gbase, int ginst, int gcnt, int gwidth,
204*3cfa11baSSteen Hegelund 			       int raddr, int rinst, int rcnt, int rwidth)
205*3cfa11baSSteen Hegelund {
206*3cfa11baSSteen Hegelund 	return readl(spx5_inst_addr(iomem, gbase, ginst,
207*3cfa11baSSteen Hegelund 				     gcnt, gwidth, raddr, rinst, rcnt, rwidth));
208*3cfa11baSSteen Hegelund }
209*3cfa11baSSteen Hegelund 
210*3cfa11baSSteen Hegelund static inline void spx5_wr(u32 val, struct sparx5 *sparx5,
211*3cfa11baSSteen Hegelund 			   int id, int tinst, int tcnt,
212*3cfa11baSSteen Hegelund 			   int gbase, int ginst, int gcnt, int gwidth,
213*3cfa11baSSteen Hegelund 			   int raddr, int rinst, int rcnt, int rwidth)
214*3cfa11baSSteen Hegelund {
215*3cfa11baSSteen Hegelund 	writel(val, spx5_addr(sparx5->regs, id, tinst, tcnt,
216*3cfa11baSSteen Hegelund 			      gbase, ginst, gcnt, gwidth,
217*3cfa11baSSteen Hegelund 			      raddr, rinst, rcnt, rwidth));
218*3cfa11baSSteen Hegelund }
219*3cfa11baSSteen Hegelund 
220*3cfa11baSSteen Hegelund static inline void spx5_inst_wr(u32 val, void __iomem *iomem,
221*3cfa11baSSteen Hegelund 				int id, int tinst, int tcnt,
222*3cfa11baSSteen Hegelund 				int gbase, int ginst, int gcnt, int gwidth,
223*3cfa11baSSteen Hegelund 				int raddr, int rinst, int rcnt, int rwidth)
224*3cfa11baSSteen Hegelund {
225*3cfa11baSSteen Hegelund 	writel(val, spx5_inst_addr(iomem,
226*3cfa11baSSteen Hegelund 				   gbase, ginst, gcnt, gwidth,
227*3cfa11baSSteen Hegelund 				   raddr, rinst, rcnt, rwidth));
228*3cfa11baSSteen Hegelund }
229*3cfa11baSSteen Hegelund 
230*3cfa11baSSteen Hegelund static inline void spx5_rmw(u32 val, u32 mask, struct sparx5 *sparx5,
231*3cfa11baSSteen Hegelund 			    int id, int tinst, int tcnt,
232*3cfa11baSSteen Hegelund 			    int gbase, int ginst, int gcnt, int gwidth,
233*3cfa11baSSteen Hegelund 			    int raddr, int rinst, int rcnt, int rwidth)
234*3cfa11baSSteen Hegelund {
235*3cfa11baSSteen Hegelund 	u32 nval;
236*3cfa11baSSteen Hegelund 
237*3cfa11baSSteen Hegelund 	nval = readl(spx5_addr(sparx5->regs, id, tinst, tcnt, gbase, ginst,
238*3cfa11baSSteen Hegelund 			       gcnt, gwidth, raddr, rinst, rcnt, rwidth));
239*3cfa11baSSteen Hegelund 	nval = (nval & ~mask) | (val & mask);
240*3cfa11baSSteen Hegelund 	writel(nval, spx5_addr(sparx5->regs, id, tinst, tcnt, gbase, ginst,
241*3cfa11baSSteen Hegelund 			       gcnt, gwidth, raddr, rinst, rcnt, rwidth));
242*3cfa11baSSteen Hegelund }
243*3cfa11baSSteen Hegelund 
244*3cfa11baSSteen Hegelund static inline void spx5_inst_rmw(u32 val, u32 mask, void __iomem *iomem,
245*3cfa11baSSteen Hegelund 				 int id, int tinst, int tcnt,
246*3cfa11baSSteen Hegelund 				 int gbase, int ginst, int gcnt, int gwidth,
247*3cfa11baSSteen Hegelund 				 int raddr, int rinst, int rcnt, int rwidth)
248*3cfa11baSSteen Hegelund {
249*3cfa11baSSteen Hegelund 	u32 nval;
250*3cfa11baSSteen Hegelund 
251*3cfa11baSSteen Hegelund 	nval = readl(spx5_inst_addr(iomem, gbase, ginst, gcnt, gwidth, raddr,
252*3cfa11baSSteen Hegelund 				    rinst, rcnt, rwidth));
253*3cfa11baSSteen Hegelund 	nval = (nval & ~mask) | (val & mask);
254*3cfa11baSSteen Hegelund 	writel(nval, spx5_inst_addr(iomem, gbase, ginst, gcnt, gwidth, raddr,
255*3cfa11baSSteen Hegelund 				    rinst, rcnt, rwidth));
256*3cfa11baSSteen Hegelund }
257*3cfa11baSSteen Hegelund 
258*3cfa11baSSteen Hegelund static inline void __iomem *spx5_inst_get(struct sparx5 *sparx5, int id, int tinst)
259*3cfa11baSSteen Hegelund {
260*3cfa11baSSteen Hegelund 	return sparx5->regs[id + tinst];
261*3cfa11baSSteen Hegelund }
262*3cfa11baSSteen Hegelund 
263*3cfa11baSSteen Hegelund static inline void __iomem *spx5_reg_get(struct sparx5 *sparx5,
264*3cfa11baSSteen Hegelund 					 int id, int tinst, int tcnt,
265*3cfa11baSSteen Hegelund 					 int gbase, int ginst, int gcnt, int gwidth,
266*3cfa11baSSteen Hegelund 					 int raddr, int rinst, int rcnt, int rwidth)
267*3cfa11baSSteen Hegelund {
268*3cfa11baSSteen Hegelund 	return spx5_addr(sparx5->regs, id, tinst, tcnt,
269*3cfa11baSSteen Hegelund 			 gbase, ginst, gcnt, gwidth,
270*3cfa11baSSteen Hegelund 			 raddr, rinst, rcnt, rwidth);
271*3cfa11baSSteen Hegelund }
272*3cfa11baSSteen Hegelund 
273*3cfa11baSSteen Hegelund #endif	/* __SPARX5_MAIN_H__ */
274