mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-08-08 08:16:59 +02:00
mips: octeon: Add cvmx-helper-agl.c
Import cvmx-helper-agl.c from 2013 U-Boot. It will be used by the later added drivers to support networking on the MIPS Octeon II / III platforms. Signed-off-by: Aaron Williams <awilliams@marvell.com> Signed-off-by: Stefan Roese <sr@denx.de>
This commit is contained in:
parent
98036b0d70
commit
bbdae2ec26
231
arch/mips/mach-octeon/cvmx-helper-agl.c
Normal file
231
arch/mips/mach-octeon/cvmx-helper-agl.c
Normal file
@ -0,0 +1,231 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018-2022 Marvell International Ltd.
|
||||
*
|
||||
* Functions for AGL (RGMII) initialization, configuration,
|
||||
* and monitoring.
|
||||
*/
|
||||
|
||||
#include <log.h>
|
||||
#include <time.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/cvmx-fuse.h>
|
||||
#include <mach/octeon-feature.h>
|
||||
#include <mach/cvmx-qlm.h>
|
||||
#include <mach/octeon_qlm.h>
|
||||
#include <mach/cvmx-pcie.h>
|
||||
#include <mach/cvmx-coremask.h>
|
||||
|
||||
#include <mach/cvmx-helper.h>
|
||||
#include <mach/cvmx-helper-cfg.h>
|
||||
|
||||
#include <mach/cvmx-agl.h>
|
||||
#include <mach/cvmx-pki.h>
|
||||
|
||||
#include <mach/cvmx-agl-defs.h>
|
||||
#include <mach/cvmx-pko-defs.h>
|
||||
|
||||
int __cvmx_helper_agl_enumerate(int xiface)
|
||||
{
|
||||
if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {
|
||||
union cvmx_agl_prtx_ctl agl_prtx_ctl;
|
||||
|
||||
agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(0));
|
||||
if (agl_prtx_ctl.s.mode == 0) /* RGMII */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @INTERNAL
|
||||
* Convert interface to port to assess CSRs.
|
||||
*
|
||||
* @param xiface Interface to probe
|
||||
* @return The port corresponding to the interface
|
||||
*/
|
||||
int cvmx_helper_agl_get_port(int xiface)
|
||||
{
|
||||
struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
|
||||
|
||||
if (OCTEON_IS_MODEL(OCTEON_CN70XX))
|
||||
return xi.interface - 4;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @INTERNAL
|
||||
* Probe a RGMII interface and determine the number of ports
|
||||
* connected to it. The RGMII interface should still be down
|
||||
* after this call.
|
||||
*
|
||||
* @param interface to probe
|
||||
*
|
||||
* @return Number of ports on the interface. Zero to disable.
|
||||
*/
|
||||
int __cvmx_helper_agl_probe(int interface)
|
||||
{
|
||||
int port = cvmx_helper_agl_get_port(interface);
|
||||
union cvmx_agl_gmx_bist gmx_bist;
|
||||
union cvmx_agl_gmx_prtx_cfg gmx_prtx_cfg;
|
||||
union cvmx_agl_prtx_ctl agl_prtx_ctl;
|
||||
int result;
|
||||
|
||||
result = __cvmx_helper_agl_enumerate(interface);
|
||||
if (result == 0)
|
||||
return 0;
|
||||
|
||||
/* Check BIST status */
|
||||
gmx_bist.u64 = csr_rd(CVMX_AGL_GMX_BIST);
|
||||
if (gmx_bist.u64)
|
||||
printf("Management port AGL failed BIST (0x%016llx) on AGL%d\n",
|
||||
CAST64(gmx_bist.u64), port);
|
||||
|
||||
/* Disable the external input/output */
|
||||
gmx_prtx_cfg.u64 = csr_rd(CVMX_AGL_GMX_PRTX_CFG(port));
|
||||
gmx_prtx_cfg.s.en = 0;
|
||||
csr_wr(CVMX_AGL_GMX_PRTX_CFG(port), gmx_prtx_cfg.u64);
|
||||
|
||||
/* Set the rgx_ref_clk MUX with AGL_PRTx_CTL[REFCLK_SEL]. Default value
|
||||
* is 0 (RGMII REFCLK). Recommended to use RGMII RXC(1) or sclk/4 (2)
|
||||
* to save cost.
|
||||
*/
|
||||
|
||||
agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(port));
|
||||
agl_prtx_ctl.s.clkrst = 0;
|
||||
agl_prtx_ctl.s.dllrst = 0;
|
||||
agl_prtx_ctl.s.clktx_byp = 0;
|
||||
|
||||
if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {
|
||||
bool tx_enable_bypass;
|
||||
int tx_delay;
|
||||
|
||||
agl_prtx_ctl.s.refclk_sel =
|
||||
cvmx_helper_get_agl_refclk_sel(interface, port);
|
||||
agl_prtx_ctl.s.clkrx_set =
|
||||
cvmx_helper_get_agl_rx_clock_skew(interface, port);
|
||||
agl_prtx_ctl.s.clkrx_byp =
|
||||
cvmx_helper_get_agl_rx_clock_delay_bypass(interface,
|
||||
port);
|
||||
cvmx_helper_cfg_get_rgmii_tx_clk_delay(
|
||||
interface, port, &tx_enable_bypass, &tx_delay);
|
||||
agl_prtx_ctl.s.clktx_byp = tx_enable_bypass;
|
||||
agl_prtx_ctl.s.clktx_set = tx_delay;
|
||||
}
|
||||
csr_wr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64);
|
||||
/* Force write out before wait */
|
||||
csr_rd(CVMX_AGL_PRTX_CTL(port));
|
||||
udelay(500);
|
||||
|
||||
/* Enable the componsation controller */
|
||||
agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(port));
|
||||
agl_prtx_ctl.s.drv_byp = 0;
|
||||
csr_wr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64);
|
||||
/* Force write out before wait */
|
||||
csr_rd(CVMX_AGL_PRTX_CTL(port));
|
||||
|
||||
if (!OCTEON_IS_OCTEON3()) {
|
||||
/* Enable the interface */
|
||||
agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(port));
|
||||
agl_prtx_ctl.s.enable = 1;
|
||||
csr_wr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64);
|
||||
/* Read the value back to force the previous write */
|
||||
agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(port));
|
||||
}
|
||||
|
||||
/* Enable the compensation controller */
|
||||
agl_prtx_ctl.u64 = csr_rd(CVMX_AGL_PRTX_CTL(port));
|
||||
agl_prtx_ctl.s.comp = 1;
|
||||
csr_wr(CVMX_AGL_PRTX_CTL(port), agl_prtx_ctl.u64);
|
||||
/* Force write out before wait */
|
||||
csr_rd(CVMX_AGL_PRTX_CTL(port));
|
||||
|
||||
/* for componsation state to lock. */
|
||||
udelay(500);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @INTERNAL
|
||||
* Bringup and enable a RGMII 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_agl_enable(int interface)
|
||||
{
|
||||
int port = cvmx_helper_agl_get_port(interface);
|
||||
int ipd_port = cvmx_helper_get_ipd_port(interface, port);
|
||||
union cvmx_pko_mem_port_ptrs pko_mem_port_ptrs;
|
||||
union cvmx_pko_reg_read_idx read_idx;
|
||||
int do_link_set = 1;
|
||||
int i;
|
||||
|
||||
/* Setup PKO for AGL interface. Back pressure is not supported. */
|
||||
pko_mem_port_ptrs.u64 = 0;
|
||||
read_idx.u64 = 0;
|
||||
read_idx.s.inc = 1;
|
||||
csr_wr(CVMX_PKO_REG_READ_IDX, read_idx.u64);
|
||||
|
||||
for (i = 0; i < 40; i++) {
|
||||
pko_mem_port_ptrs.u64 = csr_rd(CVMX_PKO_MEM_PORT_PTRS);
|
||||
if (pko_mem_port_ptrs.s.pid == 24) {
|
||||
pko_mem_port_ptrs.s.eid = 10;
|
||||
pko_mem_port_ptrs.s.bp_port = 40;
|
||||
csr_wr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cvmx_agl_enable(port);
|
||||
if (do_link_set)
|
||||
cvmx_agl_link_set(port, cvmx_agl_link_get(ipd_port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @INTERNAL
|
||||
* Return the link state of an IPD/PKO port as returned by
|
||||
* auto negotiation. The result of this function may not match
|
||||
* Octeon's link config if auto negotiation has changed since
|
||||
* the last call to cvmx_helper_link_set().
|
||||
*
|
||||
* @param ipd_port IPD/PKO port to query
|
||||
*
|
||||
* @return Link state
|
||||
*/
|
||||
cvmx_helper_link_info_t __cvmx_helper_agl_link_get(int ipd_port)
|
||||
{
|
||||
return cvmx_agl_link_get(ipd_port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @INTERNAL
|
||||
* Configure an IPD/PKO port for the specified link state. This
|
||||
* function does not influence auto negotiation at the PHY level.
|
||||
* The passed link state must always match the link state returned
|
||||
* by cvmx_helper_link_get(). It is normally best to use
|
||||
* cvmx_helper_link_autoconf() instead.
|
||||
*
|
||||
* @param ipd_port IPD/PKO port to configure
|
||||
* @param link_info The new link state
|
||||
*
|
||||
* @return Zero on success, negative on failure
|
||||
*/
|
||||
int __cvmx_helper_agl_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
|
||||
{
|
||||
int interface = cvmx_helper_get_interface_num(ipd_port);
|
||||
int port = cvmx_helper_agl_get_port(interface);
|
||||
|
||||
return cvmx_agl_link_set(port, link_info);
|
||||
}
|
Loading…
Reference in New Issue
Block a user