uboot/arch/mips/mach-octeon/cvmx-helper-agl.c
<<
>>
Prefs
   1// 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}
 232