mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-15 07:43:07 +00:00
179 lines
4.5 KiB
C
179 lines
4.5 KiB
C
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
/*
|
||
|
* Copyright (C) 2018-2022 Marvell International Ltd.
|
||
|
*
|
||
|
* Functions for LOOP initialization, configuration,
|
||
|
* and monitoring.
|
||
|
*/
|
||
|
|
||
|
#include <log.h>
|
||
|
#include <malloc.h>
|
||
|
#include <net.h>
|
||
|
#include <linux/delay.h>
|
||
|
|
||
|
#include <mach/cvmx-regs.h>
|
||
|
#include <mach/cvmx-csr.h>
|
||
|
#include <mach/cvmx-bootmem.h>
|
||
|
#include <mach/octeon-model.h>
|
||
|
#include <mach/octeon_fdt.h>
|
||
|
#include <mach/cvmx-helper.h>
|
||
|
#include <mach/cvmx-helper-board.h>
|
||
|
#include <mach/cvmx-helper-cfg.h>
|
||
|
#include <mach/cvmx-helper-fdt.h>
|
||
|
#include <mach/cvmx-helper-gpio.h>
|
||
|
|
||
|
#include <mach/cvmx-agl-defs.h>
|
||
|
#include <mach/cvmx-bgxx-defs.h>
|
||
|
#include <mach/cvmx-ciu-defs.h>
|
||
|
#include <mach/cvmx-gmxx-defs.h>
|
||
|
#include <mach/cvmx-gserx-defs.h>
|
||
|
#include <mach/cvmx-ilk-defs.h>
|
||
|
#include <mach/cvmx-ipd-defs.h>
|
||
|
#include <mach/cvmx-lbk-defs.h>
|
||
|
#include <mach/cvmx-pcsx-defs.h>
|
||
|
#include <mach/cvmx-pcsxx-defs.h>
|
||
|
#include <mach/cvmx-pki-defs.h>
|
||
|
#include <mach/cvmx-pko-defs.h>
|
||
|
#include <mach/cvmx-xcv-defs.h>
|
||
|
|
||
|
#include <mach/cvmx-hwpko.h>
|
||
|
#include <mach/cvmx-ilk.h>
|
||
|
#include <mach/cvmx-pki.h>
|
||
|
|
||
|
int __cvmx_helper_loop_enumerate(int xiface)
|
||
|
{
|
||
|
return OCTEON_IS_MODEL(OCTEON_CN68XX) ?
|
||
|
8 : (OCTEON_IS_MODEL(OCTEON_CNF71XX) ? 2 : 4);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @INTERNAL
|
||
|
* Probe a LOOP interface and determine the number of ports
|
||
|
* connected to it. The LOOP interface should still be down
|
||
|
* after this call.
|
||
|
*
|
||
|
* @param xiface Interface to probe
|
||
|
*
|
||
|
* @return Number of ports on the interface. Zero to disable.
|
||
|
*/
|
||
|
int __cvmx_helper_loop_probe(int xiface)
|
||
|
{
|
||
|
return __cvmx_helper_loop_enumerate(xiface);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @INTERNAL
|
||
|
* Bringup and enable a LOOP interface. After this call packet
|
||
|
* I/O should be fully functional. This is called with IPD
|
||
|
* enabled but PKO disabled.
|
||
|
*
|
||
|
* @param interface to bring up
|
||
|
*
|
||
|
* @return Zero on success, negative on failure
|
||
|
*/
|
||
|
int __cvmx_helper_loop_enable(int xiface)
|
||
|
{
|
||
|
cvmx_pip_prt_cfgx_t port_cfg;
|
||
|
int num_ports, index;
|
||
|
unsigned long offset;
|
||
|
struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
|
||
|
|
||
|
num_ports = __cvmx_helper_get_num_ipd_ports(xiface);
|
||
|
/*
|
||
|
* We need to disable length checking so packet < 64 bytes and jumbo
|
||
|
* frames don't get errors
|
||
|
*/
|
||
|
for (index = 0; index < num_ports; index++) {
|
||
|
offset = ((octeon_has_feature(OCTEON_FEATURE_PKND)) ?
|
||
|
cvmx_helper_get_pknd(xiface, index) :
|
||
|
cvmx_helper_get_ipd_port(xiface, index));
|
||
|
|
||
|
if (octeon_has_feature(OCTEON_FEATURE_PKI)) {
|
||
|
cvmx_pki_endis_l2_errs(xi.node, offset, 1, 0, 0);
|
||
|
cvmx_pki_endis_fcs_check(xi.node, offset, 0, 0);
|
||
|
} else {
|
||
|
port_cfg.u64 = csr_rd(CVMX_PIP_PRT_CFGX(offset));
|
||
|
port_cfg.s.maxerr_en = 0;
|
||
|
port_cfg.s.minerr_en = 0;
|
||
|
csr_wr(CVMX_PIP_PRT_CFGX(offset), port_cfg.u64);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Disable FCS stripping for loopback ports
|
||
|
*/
|
||
|
if (!octeon_has_feature(OCTEON_FEATURE_PKND)) {
|
||
|
cvmx_ipd_sub_port_fcs_t ipd_sub_port_fcs;
|
||
|
|
||
|
ipd_sub_port_fcs.u64 = csr_rd(CVMX_IPD_SUB_PORT_FCS);
|
||
|
ipd_sub_port_fcs.s.port_bit2 = 0;
|
||
|
csr_wr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
|
||
|
}
|
||
|
/*
|
||
|
* Set PKND and BPID for loopback ports.
|
||
|
*/
|
||
|
if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
|
||
|
cvmx_pko_reg_loopback_pkind_t lp_pknd;
|
||
|
cvmx_pko_reg_loopback_bpid_t lp_bpid;
|
||
|
|
||
|
for (index = 0; index < num_ports; index++) {
|
||
|
int pknd = cvmx_helper_get_pknd(xiface, index);
|
||
|
int bpid = cvmx_helper_get_bpid(xiface, index);
|
||
|
|
||
|
lp_pknd.u64 = csr_rd(CVMX_PKO_REG_LOOPBACK_PKIND);
|
||
|
lp_bpid.u64 = csr_rd(CVMX_PKO_REG_LOOPBACK_BPID);
|
||
|
|
||
|
if (index == 0)
|
||
|
lp_pknd.s.num_ports = num_ports;
|
||
|
|
||
|
switch (index) {
|
||
|
case 0:
|
||
|
lp_pknd.s.pkind0 = pknd;
|
||
|
lp_bpid.s.bpid0 = bpid;
|
||
|
break;
|
||
|
case 1:
|
||
|
lp_pknd.s.pkind1 = pknd;
|
||
|
lp_bpid.s.bpid1 = bpid;
|
||
|
break;
|
||
|
case 2:
|
||
|
lp_pknd.s.pkind2 = pknd;
|
||
|
lp_bpid.s.bpid2 = bpid;
|
||
|
break;
|
||
|
case 3:
|
||
|
lp_pknd.s.pkind3 = pknd;
|
||
|
lp_bpid.s.bpid3 = bpid;
|
||
|
break;
|
||
|
case 4:
|
||
|
lp_pknd.s.pkind4 = pknd;
|
||
|
lp_bpid.s.bpid4 = bpid;
|
||
|
break;
|
||
|
case 5:
|
||
|
lp_pknd.s.pkind5 = pknd;
|
||
|
lp_bpid.s.bpid5 = bpid;
|
||
|
break;
|
||
|
case 6:
|
||
|
lp_pknd.s.pkind6 = pknd;
|
||
|
lp_bpid.s.bpid6 = bpid;
|
||
|
break;
|
||
|
case 7:
|
||
|
lp_pknd.s.pkind7 = pknd;
|
||
|
lp_bpid.s.bpid7 = bpid;
|
||
|
break;
|
||
|
}
|
||
|
csr_wr(CVMX_PKO_REG_LOOPBACK_PKIND, lp_pknd.u64);
|
||
|
csr_wr(CVMX_PKO_REG_LOOPBACK_BPID, lp_bpid.u64);
|
||
|
}
|
||
|
} else if (octeon_has_feature(OCTEON_FEATURE_BGX)) {
|
||
|
cvmx_lbk_chx_pkind_t lbk_pkind;
|
||
|
|
||
|
for (index = 0; index < num_ports; index++) {
|
||
|
lbk_pkind.u64 = 0;
|
||
|
lbk_pkind.s.pkind = cvmx_helper_get_pknd(xiface, index);
|
||
|
csr_wr_node(xi.node, CVMX_LBK_CHX_PKIND(index),
|
||
|
lbk_pkind.u64);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|