1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018-2022 Marvell International Ltd.
4  *
5  * Functions for LOOP initialization, configuration,
6  * and monitoring.
7  */
8 
9 #include <log.h>
10 #include <malloc.h>
11 #include <net.h>
12 #include <linux/delay.h>
13 
14 #include <mach/cvmx-regs.h>
15 #include <mach/cvmx-csr.h>
16 #include <mach/cvmx-bootmem.h>
17 #include <mach/octeon-model.h>
18 #include <mach/octeon_fdt.h>
19 #include <mach/cvmx-helper.h>
20 #include <mach/cvmx-helper-board.h>
21 #include <mach/cvmx-helper-cfg.h>
22 #include <mach/cvmx-helper-fdt.h>
23 #include <mach/cvmx-helper-gpio.h>
24 
25 #include <mach/cvmx-agl-defs.h>
26 #include <mach/cvmx-bgxx-defs.h>
27 #include <mach/cvmx-ciu-defs.h>
28 #include <mach/cvmx-gmxx-defs.h>
29 #include <mach/cvmx-gserx-defs.h>
30 #include <mach/cvmx-ilk-defs.h>
31 #include <mach/cvmx-ipd-defs.h>
32 #include <mach/cvmx-lbk-defs.h>
33 #include <mach/cvmx-pcsx-defs.h>
34 #include <mach/cvmx-pcsxx-defs.h>
35 #include <mach/cvmx-pki-defs.h>
36 #include <mach/cvmx-pko-defs.h>
37 #include <mach/cvmx-xcv-defs.h>
38 
39 #include <mach/cvmx-hwpko.h>
40 #include <mach/cvmx-ilk.h>
41 #include <mach/cvmx-pki.h>
42 
__cvmx_helper_loop_enumerate(int xiface)43 int __cvmx_helper_loop_enumerate(int xiface)
44 {
45 	return OCTEON_IS_MODEL(OCTEON_CN68XX) ?
46 		       8 : (OCTEON_IS_MODEL(OCTEON_CNF71XX) ? 2 : 4);
47 }
48 
49 /**
50  * @INTERNAL
51  * Probe a LOOP interface and determine the number of ports
52  * connected to it. The LOOP interface should still be down
53  * after this call.
54  *
55  * @param xiface Interface to probe
56  *
57  * @return Number of ports on the interface. Zero to disable.
58  */
__cvmx_helper_loop_probe(int xiface)59 int __cvmx_helper_loop_probe(int xiface)
60 {
61 	return __cvmx_helper_loop_enumerate(xiface);
62 }
63 
64 /**
65  * @INTERNAL
66  * Bringup and enable a LOOP interface. After this call packet
67  * I/O should be fully functional. This is called with IPD
68  * enabled but PKO disabled.
69  *
70  * @param interface to bring up
71  *
72  * @return Zero on success, negative on failure
73  */
__cvmx_helper_loop_enable(int xiface)74 int __cvmx_helper_loop_enable(int xiface)
75 {
76 	cvmx_pip_prt_cfgx_t port_cfg;
77 	int num_ports, index;
78 	unsigned long offset;
79 	struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
80 
81 	num_ports = __cvmx_helper_get_num_ipd_ports(xiface);
82 	/*
83 	 * We need to disable length checking so packet < 64 bytes and jumbo
84 	 * frames don't get errors
85 	 */
86 	for (index = 0; index < num_ports; index++) {
87 		offset = ((octeon_has_feature(OCTEON_FEATURE_PKND)) ?
88 				  cvmx_helper_get_pknd(xiface, index) :
89 					cvmx_helper_get_ipd_port(xiface, index));
90 
91 		if (octeon_has_feature(OCTEON_FEATURE_PKI)) {
92 			cvmx_pki_endis_l2_errs(xi.node, offset, 1, 0, 0);
93 			cvmx_pki_endis_fcs_check(xi.node, offset, 0, 0);
94 		} else {
95 			port_cfg.u64 = csr_rd(CVMX_PIP_PRT_CFGX(offset));
96 			port_cfg.s.maxerr_en = 0;
97 			port_cfg.s.minerr_en = 0;
98 			csr_wr(CVMX_PIP_PRT_CFGX(offset), port_cfg.u64);
99 		}
100 	}
101 
102 	/*
103 	 * Disable FCS stripping for loopback ports
104 	 */
105 	if (!octeon_has_feature(OCTEON_FEATURE_PKND)) {
106 		cvmx_ipd_sub_port_fcs_t ipd_sub_port_fcs;
107 
108 		ipd_sub_port_fcs.u64 = csr_rd(CVMX_IPD_SUB_PORT_FCS);
109 		ipd_sub_port_fcs.s.port_bit2 = 0;
110 		csr_wr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
111 	}
112 	/*
113 	 * Set PKND and BPID for loopback ports.
114 	 */
115 	if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
116 		cvmx_pko_reg_loopback_pkind_t lp_pknd;
117 		cvmx_pko_reg_loopback_bpid_t lp_bpid;
118 
119 		for (index = 0; index < num_ports; index++) {
120 			int pknd = cvmx_helper_get_pknd(xiface, index);
121 			int bpid = cvmx_helper_get_bpid(xiface, index);
122 
123 			lp_pknd.u64 = csr_rd(CVMX_PKO_REG_LOOPBACK_PKIND);
124 			lp_bpid.u64 = csr_rd(CVMX_PKO_REG_LOOPBACK_BPID);
125 
126 			if (index == 0)
127 				lp_pknd.s.num_ports = num_ports;
128 
129 			switch (index) {
130 			case 0:
131 				lp_pknd.s.pkind0 = pknd;
132 				lp_bpid.s.bpid0 = bpid;
133 				break;
134 			case 1:
135 				lp_pknd.s.pkind1 = pknd;
136 				lp_bpid.s.bpid1 = bpid;
137 				break;
138 			case 2:
139 				lp_pknd.s.pkind2 = pknd;
140 				lp_bpid.s.bpid2 = bpid;
141 				break;
142 			case 3:
143 				lp_pknd.s.pkind3 = pknd;
144 				lp_bpid.s.bpid3 = bpid;
145 				break;
146 			case 4:
147 				lp_pknd.s.pkind4 = pknd;
148 				lp_bpid.s.bpid4 = bpid;
149 				break;
150 			case 5:
151 				lp_pknd.s.pkind5 = pknd;
152 				lp_bpid.s.bpid5 = bpid;
153 				break;
154 			case 6:
155 				lp_pknd.s.pkind6 = pknd;
156 				lp_bpid.s.bpid6 = bpid;
157 				break;
158 			case 7:
159 				lp_pknd.s.pkind7 = pknd;
160 				lp_bpid.s.bpid7 = bpid;
161 				break;
162 			}
163 			csr_wr(CVMX_PKO_REG_LOOPBACK_PKIND, lp_pknd.u64);
164 			csr_wr(CVMX_PKO_REG_LOOPBACK_BPID, lp_bpid.u64);
165 		}
166 	} else if (octeon_has_feature(OCTEON_FEATURE_BGX)) {
167 		cvmx_lbk_chx_pkind_t lbk_pkind;
168 
169 		for (index = 0; index < num_ports; index++) {
170 			lbk_pkind.u64 = 0;
171 			lbk_pkind.s.pkind = cvmx_helper_get_pknd(xiface, index);
172 			csr_wr_node(xi.node, CVMX_LBK_CHX_PKIND(index),
173 				    lbk_pkind.u64);
174 		}
175 	}
176 
177 	return 0;
178 }
179