1 // SPDX-License-Identifier:    GPL-2.0
2 /*
3  * Copyright (C) 2018 Marvell International Ltd.
4  */
5 
6 #include <dm.h>
7 #include <errno.h>
8 #include <malloc.h>
9 #include <misc.h>
10 #include <net.h>
11 #include <pci_ids.h>
12 #include <linux/list.h>
13 #include <asm/arch/board.h>
14 #include <asm/arch/csrs/csrs-cgx.h>
15 #include <asm/io.h>
16 
17 #include "cgx.h"
18 
19 char lmac_type_to_str[][8] = {
20 	"SGMII",
21 	"XAUI",
22 	"RXAUI",
23 	"10G_R",
24 	"40G_R",
25 	"RGMII",
26 	"QSGMII",
27 	"25G_R",
28 	"50G_R",
29 	"100G_R",
30 	"USXGMII",
31 };
32 
33 char lmac_speed_to_str[][8] = {
34 	"0",
35 	"10M",
36 	"100M",
37 	"1G",
38 	"2.5G",
39 	"5G",
40 	"10G",
41 	"20G",
42 	"25G",
43 	"40G",
44 	"50G",
45 	"80G",
46 	"100G",
47 };
48 
49 /**
50  * Given an LMAC/PF instance number, return the lmac
51  * Per design, each PF has only one LMAC mapped.
52  *
53  * @param instance	instance to find
54  *
55  * @return	pointer to lmac data structure or NULL if not found
56  */
nix_get_cgx_lmac(int lmac_instance)57 struct lmac *nix_get_cgx_lmac(int lmac_instance)
58 {
59 	struct cgx *cgx;
60 	struct udevice *dev;
61 	int i, idx, err;
62 
63 	for (i = 0; i < CGX_PER_NODE; i++) {
64 		err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
65 					 PCI_DEVICE_ID_OCTEONTX2_CGX, i,
66 					 &dev);
67 		if (err)
68 			continue;
69 
70 		cgx = dev_get_priv(dev);
71 		debug("%s udev %p cgx %p instance %d\n", __func__, dev, cgx,
72 		      lmac_instance);
73 		for (idx = 0; idx < cgx->lmac_count; idx++) {
74 			if (cgx->lmac[idx]->instance == lmac_instance)
75 				return cgx->lmac[idx];
76 		}
77 	}
78 	return NULL;
79 }
80 
cgx_lmac_mac_filter_clear(struct lmac * lmac)81 void cgx_lmac_mac_filter_clear(struct lmac *lmac)
82 {
83 	union cgxx_cmrx_rx_dmac_ctl0 dmac_ctl0;
84 	union cgxx_cmr_rx_dmacx_cam0 dmac_cam0;
85 	void *reg_addr;
86 
87 	dmac_cam0.u = 0x0;
88 	reg_addr = lmac->cgx->reg_base +
89 			CGXX_CMR_RX_DMACX_CAM0(lmac->lmac_id * 8);
90 	writeq(dmac_cam0.u, reg_addr);
91 	debug("%s: reg %p dmac_cam0 %llx\n", __func__, reg_addr, dmac_cam0.u);
92 
93 	dmac_ctl0.u = 0x0;
94 	dmac_ctl0.s.bcst_accept = 1;
95 	dmac_ctl0.s.mcst_mode = 1;
96 	dmac_ctl0.s.cam_accept = 0;
97 	reg_addr = lmac->cgx->reg_base +
98 			CGXX_CMRX_RX_DMAC_CTL0(lmac->lmac_id);
99 	writeq(dmac_ctl0.u, reg_addr);
100 	debug("%s: reg %p dmac_ctl0 %llx\n", __func__, reg_addr, dmac_ctl0.u);
101 }
102 
cgx_lmac_mac_filter_setup(struct lmac * lmac)103 void cgx_lmac_mac_filter_setup(struct lmac *lmac)
104 {
105 	union cgxx_cmrx_rx_dmac_ctl0 dmac_ctl0;
106 	union cgxx_cmr_rx_dmacx_cam0 dmac_cam0;
107 	u64 mac, tmp;
108 	void *reg_addr;
109 
110 	memcpy((void *)&tmp, lmac->mac_addr, 6);
111 	debug("%s: tmp %llx\n", __func__, tmp);
112 	debug("%s: swab tmp %llx\n", __func__, swab64(tmp));
113 	mac = swab64(tmp) >> 16;
114 	debug("%s: mac %llx\n", __func__, mac);
115 	dmac_cam0.u = 0x0;
116 	dmac_cam0.s.id = lmac->lmac_id;
117 	dmac_cam0.s.adr = mac;
118 	dmac_cam0.s.en = 1;
119 	reg_addr = lmac->cgx->reg_base +
120 			CGXX_CMR_RX_DMACX_CAM0(lmac->lmac_id * 8);
121 	writeq(dmac_cam0.u, reg_addr);
122 	debug("%s: reg %p dmac_cam0 %llx\n", __func__, reg_addr, dmac_cam0.u);
123 	dmac_ctl0.u = 0x0;
124 	dmac_ctl0.s.bcst_accept = 1;
125 	dmac_ctl0.s.mcst_mode = 0;
126 	dmac_ctl0.s.cam_accept = 1;
127 	reg_addr = lmac->cgx->reg_base +
128 			CGXX_CMRX_RX_DMAC_CTL0(lmac->lmac_id);
129 	writeq(dmac_ctl0.u, reg_addr);
130 	debug("%s: reg %p dmac_ctl0 %llx\n", __func__, reg_addr, dmac_ctl0.u);
131 }
132 
cgx_lmac_set_pkind(struct lmac * lmac,u8 lmac_id,int pkind)133 int cgx_lmac_set_pkind(struct lmac *lmac, u8 lmac_id, int pkind)
134 {
135 	cgx_write(lmac->cgx, lmac_id, CGXX_CMRX_RX_ID_MAP(0),
136 		  (pkind & 0x3f));
137 	return 0;
138 }
139 
cgx_lmac_link_status(struct lmac * lmac,int lmac_id,u64 * status)140 int cgx_lmac_link_status(struct lmac *lmac, int lmac_id, u64 *status)
141 {
142 	int ret = 0;
143 
144 	ret = cgx_intf_get_link_sts(lmac->cgx->cgx_id, lmac_id, status);
145 	if (ret) {
146 		debug("%s request failed for cgx%d lmac%d\n",
147 		      __func__, lmac->cgx->cgx_id, lmac->lmac_id);
148 		ret = -1;
149 	}
150 	return ret;
151 }
152 
cgx_lmac_rx_tx_enable(struct lmac * lmac,int lmac_id,bool enable)153 int cgx_lmac_rx_tx_enable(struct lmac *lmac, int lmac_id, bool enable)
154 {
155 	struct cgx *cgx = lmac->cgx;
156 	union cgxx_cmrx_config cmrx_config;
157 
158 	if (!cgx || lmac_id >= cgx->lmac_count)
159 		return -ENODEV;
160 
161 	cmrx_config.u = cgx_read(cgx, lmac_id, CGXX_CMRX_CONFIG(0));
162 	cmrx_config.s.data_pkt_rx_en =
163 	cmrx_config.s.data_pkt_tx_en = enable ? 1 : 0;
164 	cgx_write(cgx, lmac_id, CGXX_CMRX_CONFIG(0), cmrx_config.u);
165 	return 0;
166 }
167 
cgx_lmac_link_enable(struct lmac * lmac,int lmac_id,bool enable,u64 * status)168 int cgx_lmac_link_enable(struct lmac *lmac, int lmac_id, bool enable,
169 			 u64 *status)
170 {
171 	int ret = 0;
172 
173 	ret = cgx_intf_link_up_dwn(lmac->cgx->cgx_id, lmac_id, enable,
174 				   status);
175 	if (ret) {
176 		debug("%s request failed for cgx%d lmac%d\n",
177 		      __func__, lmac->cgx->cgx_id, lmac->lmac_id);
178 		ret = -1;
179 	}
180 	return ret;
181 }
182 
cgx_lmac_internal_loopback(struct lmac * lmac,int lmac_id,bool enable)183 int cgx_lmac_internal_loopback(struct lmac *lmac, int lmac_id, bool enable)
184 {
185 	struct cgx *cgx = lmac->cgx;
186 	union cgxx_cmrx_config cmrx_cfg;
187 	union cgxx_gmp_pcs_mrx_control mrx_control;
188 	union cgxx_spux_control1 spux_control1;
189 	enum lmac_type lmac_type;
190 
191 	if (!cgx || lmac_id >= cgx->lmac_count)
192 		return -ENODEV;
193 
194 	cmrx_cfg.u = cgx_read(cgx, lmac_id, CGXX_CMRX_CONFIG(0));
195 	lmac_type = cmrx_cfg.s.lmac_type;
196 	if (lmac_type == LMAC_MODE_SGMII || lmac_type == LMAC_MODE_QSGMII) {
197 		mrx_control.u = cgx_read(cgx, lmac_id,
198 					 CGXX_GMP_PCS_MRX_CONTROL(0));
199 		mrx_control.s.loopbck1 = enable ? 1 : 0;
200 		cgx_write(cgx, lmac_id, CGXX_GMP_PCS_MRX_CONTROL(0),
201 			  mrx_control.u);
202 	} else {
203 		spux_control1.u = cgx_read(cgx, lmac_id,
204 					   CGXX_SPUX_CONTROL1(0));
205 		spux_control1.s.loopbck = enable ? 1 : 0;
206 		cgx_write(cgx, lmac_id, CGXX_SPUX_CONTROL1(0),
207 			  spux_control1.u);
208 	}
209 	return 0;
210 }
211 
cgx_lmac_init(struct cgx * cgx)212 static int cgx_lmac_init(struct cgx *cgx)
213 {
214 	struct lmac *lmac;
215 	union cgxx_cmrx_config cmrx_cfg;
216 	static int instance = 1;
217 	int i;
218 
219 	cgx->lmac_count = cgx_read(cgx, 0, CGXX_CMR_RX_LMACS());
220 	debug("%s: Found %d lmacs for cgx %d@%p\n", __func__, cgx->lmac_count,
221 	      cgx->cgx_id, cgx->reg_base);
222 
223 	for (i = 0; i < cgx->lmac_count; i++) {
224 		lmac = calloc(1, sizeof(*lmac));
225 		if (!lmac)
226 			return -ENOMEM;
227 		lmac->instance = instance++;
228 		snprintf(lmac->name, sizeof(lmac->name), "cgx_fwi_%d_%d",
229 			 cgx->cgx_id, i);
230 		/* Get LMAC type */
231 		cmrx_cfg.u = cgx_read(cgx, i, CGXX_CMRX_CONFIG(0));
232 		lmac->lmac_type = cmrx_cfg.s.lmac_type;
233 
234 		lmac->lmac_id = i;
235 		lmac->cgx = cgx;
236 		cgx->lmac[i] = lmac;
237 		debug("%s: map id %d to lmac %p (%s), type:%d instance %d\n",
238 		      __func__, i, lmac, lmac->name, lmac->lmac_type,
239 		      lmac->instance);
240 		lmac->init_pend = 1;
241 		printf("CGX%d LMAC%d [%s]\n", lmac->cgx->cgx_id,
242 		       lmac->lmac_id, lmac_type_to_str[lmac->lmac_type]);
243 		octeontx2_board_get_mac_addr((lmac->instance - 1),
244 					     lmac->mac_addr);
245 		debug("%s: MAC %pM\n", __func__, lmac->mac_addr);
246 		cgx_lmac_mac_filter_setup(lmac);
247 	}
248 	return 0;
249 }
250 
cgx_probe(struct udevice * dev)251 int cgx_probe(struct udevice *dev)
252 {
253 	struct cgx *cgx = dev_get_priv(dev);
254 	int err;
255 
256 	cgx->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
257 				       PCI_REGION_MEM);
258 	cgx->dev = dev;
259 	cgx->cgx_id = ((u64)(cgx->reg_base) >> 24) & 0x7;
260 
261 	debug("%s CGX BAR %p, id: %d\n", __func__, cgx->reg_base,
262 	      cgx->cgx_id);
263 	debug("%s CGX %p, udev: %p\n", __func__, cgx, dev);
264 
265 	err = cgx_lmac_init(cgx);
266 
267 	return err;
268 }
269 
cgx_remove(struct udevice * dev)270 int cgx_remove(struct udevice *dev)
271 {
272 	struct cgx *cgx = dev_get_priv(dev);
273 	int i;
274 
275 	debug("%s: cgx remove reg_base %p cgx_id %d",
276 	      __func__, cgx->reg_base, cgx->cgx_id);
277 	for (i = 0; i < cgx->lmac_count; i++)
278 		cgx_lmac_mac_filter_clear(cgx->lmac[i]);
279 
280 	return 0;
281 }
282 
283 U_BOOT_DRIVER(cgx) = {
284 	.name	= "cgx",
285 	.id	= UCLASS_MISC,
286 	.probe	= cgx_probe,
287 	.remove	= cgx_remove,
288 	.priv_auto	= sizeof(struct cgx),
289 };
290 
291 static struct pci_device_id cgx_supported[] = {
292 	{PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_CGX) },
293 	{}
294 };
295 
296 U_BOOT_PCI_DEVICE(cgx, cgx_supported);
297