blob: 7eb99ac7c22bf9622959d023ce83eec2eb48f549 [file] [log] [blame]
Aaron Williamsbbdae2e2022-04-07 09:11:11 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018-2022 Marvell International Ltd.
4 *
5 * Functions for AGL (RGMII) initialization, configuration,
6 * and monitoring.
7 */
8
9#include <log.h>
10#include <time.h>
11#include <linux/delay.h>
12
13#include <mach/cvmx-regs.h>
14#include <mach/cvmx-csr.h>
15#include <mach/cvmx-bootmem.h>
16#include <mach/octeon-model.h>
17#include <mach/cvmx-fuse.h>
18#include <mach/octeon-feature.h>
19#include <mach/cvmx-qlm.h>
20#include <mach/octeon_qlm.h>
21#include <mach/cvmx-pcie.h>
22#include <mach/cvmx-coremask.h>
23
24#include <mach/cvmx-helper.h>
25#include <mach/cvmx-helper-cfg.h>
26
27#include <mach/cvmx-agl.h>
28#include <mach/cvmx-pki.h>
29
30#include <mach/cvmx-agl-defs.h>
31#include <mach/cvmx-pko-defs.h>
32
33int __cvmx_helper_agl_enumerate(int xiface)
34{
35 if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {
36 union cvmx_agl_prtx_ctl agl_prtx_ctl;
37
38 agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(0));
39 if (agl_prtx_ctl.s.mode == 0) /* RGMII */
40 return 1;
41 }
42 return 0;
43}
44
45/**
46 * @INTERNAL
47 * Convert interface to port to assess CSRs.
48 *
49 * @param xiface Interface to probe
50 * @return The port corresponding to the interface
51 */
52int cvmx_helper_agl_get_port(int xiface)
53{
54 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
55
56 if (OCTEON_IS_MODEL(OCTEON_CN70XX))
57 return xi.interface - 4;
58 return -1;
59}
60
61/**
62 * @INTERNAL
63 * Probe a RGMII interface and determine the number of ports
64 * connected to it. The RGMII interface should still be down
65 * after this call.
66 *
67 * @param interface to probe
68 *
69 * @return Number of ports on the interface. Zero to disable.
70 */
71int __cvmx_helper_agl_probe(int interface)
72{
73 int port = cvmx_helper_agl_get_port(interface);
74 union cvmx_agl_gmx_bist gmx_bist;
75 union cvmx_agl_gmx_prtx_cfg gmx_prtx_cfg;
76 union cvmx_agl_prtx_ctl agl_prtx_ctl;
77 int result;
78
79 result = __cvmx_helper_agl_enumerate(interface);
80 if (result == 0)
81 return 0;
82
83 /* Check BIST status */
84 gmx_bist.u64 = csr_rd(CVMX_AGL_GMX_BIST);
85 if (gmx_bist.u64)
86 printf("Management port AGL failed BIST (0x%016llx) on AGL%d\n",
87 CAST64(gmx_bist.u64), port);
88
89 /* Disable the external input/output */
90 gmx_prtx_cfg.u64 = csr_rd(CVMX_AGL_GMX_PRTX_CFG(port));
91 gmx_prtx_cfg.s.en = 0;
92 csr_wr(CVMX_AGL_GMX_PRTX_CFG(port), gmx_prtx_cfg.u64);
93
94 /* Set the rgx_ref_clk MUX with AGL_PRTx_CTL[REFCLK_SEL]. Default value
95 * is 0 (RGMII REFCLK). Recommended to use RGMII RXC(1) or sclk/4 (2)
96 * to save cost.
97 */
98
99 agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(port));
100 agl_prtx_ctl.s.clkrst = 0;
101 agl_prtx_ctl.s.dllrst = 0;
102 agl_prtx_ctl.s.clktx_byp = 0;
103
104 if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {
105 bool tx_enable_bypass;
106 int tx_delay;
107
108 agl_prtx_ctl.s.refclk_sel =
109 cvmx_helper_get_agl_refclk_sel(interface, port);
110 agl_prtx_ctl.s.clkrx_set =
111 cvmx_helper_get_agl_rx_clock_skew(interface, port);
112 agl_prtx_ctl.s.clkrx_byp =
113 cvmx_helper_get_agl_rx_clock_delay_bypass(interface,
114 port);
115 cvmx_helper_cfg_get_rgmii_tx_clk_delay(
116 interface, port, &tx_enable_bypass, &tx_delay);
117 agl_prtx_ctl.s.clktx_byp = tx_enable_bypass;
118 agl_prtx_ctl.s.clktx_set = tx_delay;
119 }
120 csr_wr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64);
121 /* Force write out before wait */
122 csr_rd(CVMX_AGL_PRTX_CTL(port));
123 udelay(500);
124
125 /* Enable the componsation controller */
126 agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(port));
127 agl_prtx_ctl.s.drv_byp = 0;
128 csr_wr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64);
129 /* Force write out before wait */
130 csr_rd(CVMX_AGL_PRTX_CTL(port));
131
132 if (!OCTEON_IS_OCTEON3()) {
133 /* Enable the interface */
134 agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(port));
135 agl_prtx_ctl.s.enable = 1;
136 csr_wr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64);
137 /* Read the value back to force the previous write */
138 agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(port));
139 }
140
141 /* Enable the compensation controller */
142 agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(port));
143 agl_prtx_ctl.s.comp = 1;
144 csr_wr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64);
145 /* Force write out before wait */
146 csr_rd(CVMX_AGL_PRTX_CTL(port));
147
148 /* for componsation state to lock. */
149 udelay(500);
150
151 return result;
152}
153
154/**
155 * @INTERNAL
156 * Bringup and enable a RGMII interface. After this call packet
157 * I/O should be fully functional. This is called with IPD
158 * enabled but PKO disabled.
159 *
160 * @param interface to bring up
161 *
162 * @return Zero on success, negative on failure
163 */
164int __cvmx_helper_agl_enable(int interface)
165{
166 int port = cvmx_helper_agl_get_port(interface);
167 int ipd_port = cvmx_helper_get_ipd_port(interface, port);
168 union cvmx_pko_mem_port_ptrs pko_mem_port_ptrs;
169 union cvmx_pko_reg_read_idx read_idx;
170 int do_link_set = 1;
171 int i;
172
173 /* Setup PKO for AGL interface. Back pressure is not supported. */
174 pko_mem_port_ptrs.u64 = 0;
175 read_idx.u64 = 0;
176 read_idx.s.inc = 1;
177 csr_wr(CVMX_PKO_REG_READ_IDX, read_idx.u64);
178
179 for (i = 0; i < 40; i++) {
180 pko_mem_port_ptrs.u64 = csr_rd(CVMX_PKO_MEM_PORT_PTRS);
181 if (pko_mem_port_ptrs.s.pid == 24) {
182 pko_mem_port_ptrs.s.eid = 10;
183 pko_mem_port_ptrs.s.bp_port = 40;
184 csr_wr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
185 break;
186 }
187 }
188
189 cvmx_agl_enable(port);
190 if (do_link_set)
191 cvmx_agl_link_set(port, cvmx_agl_link_get(ipd_port));
192
193 return 0;
194}
195
196/**
197 * @INTERNAL
198 * Return the link state of an IPD/PKO port as returned by
199 * auto negotiation. The result of this function may not match
200 * Octeon's link config if auto negotiation has changed since
201 * the last call to cvmx_helper_link_set().
202 *
203 * @param ipd_port IPD/PKO port to query
204 *
205 * @return Link state
206 */
207cvmx_helper_link_info_t __cvmx_helper_agl_link_get(int ipd_port)
208{
209 return cvmx_agl_link_get(ipd_port);
210}
211
212/**
213 * @INTERNAL
214 * Configure an IPD/PKO port for the specified link state. This
215 * function does not influence auto negotiation at the PHY level.
216 * The passed link state must always match the link state returned
217 * by cvmx_helper_link_get(). It is normally best to use
218 * cvmx_helper_link_autoconf() instead.
219 *
220 * @param ipd_port IPD/PKO port to configure
221 * @param link_info The new link state
222 *
223 * @return Zero on success, negative on failure
224 */
225int __cvmx_helper_agl_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
226{
227 int interface = cvmx_helper_get_interface_num(ipd_port);
228 int port = cvmx_helper_agl_get_port(interface);
229
230 return cvmx_agl_link_set(port, link_info);
231}