text: /** SerDes.c
    Provides SoC specific SerDes interface
  
    Copyright 2020 NXP
  
    SPDX-License-Identifier: BSD-2-Clause-Patent
  **/
  
  #include <Library/DebugLib.h>
  #include <Library/SerDesHelperLib.h>
  
  /**
    Function to get SerDes Lane protocol corresponding to
    SerDes protocol.
  
    @param  SerDes              SerDes number.
    @param  SerDesProtocol      SerDes protocol number.
    @param  Lane                SerDes Lane number.
    @param  SerDesMaxProtocol   Max SerDes protocol number.
    @param  Config              SerDes Configuration.
  
    @return SerDes Lane protocol.
  
  **/
  UINT32
  GetSerDesProtocol (
    IN  INTN            SerDes,
    IN  INTN            SerDesProtocol,
    IN  INTN            Lane,
    IN  UINT32          SerDesMaxProtocol,
    IN  SERDES_CONFIG   *Config
    )
  {
    while (Config->Protocol) {
      if (Config->Protocol == SerDesProtocol) {
        return Config->SerDesLane[Lane];
      }
      Config++;
    }
  
    return SerDesMaxProtocol;
  }
  
  /**
    Function to validate input SerDes protocol.
  
    @param  SerDes              SerDes number.
    @param  SerDesProtocol      SerDes protocol number.
    @param  SerDesNumLanes      Number of SerDes Lanes.
    @param  Config              SerDes Configuration.
  
    @return EFI_NOT_FOUND     SerDes Protocol not a valid protocol.
    @return EFI_SUCCESS       SerDes Protocol is a valid protocol.
  
  **/
  EFI_STATUS
  IsSerDesProtocolValid (
    IN  INTN           SerDes,
    IN  UINT32         SerDesProtocol,
    IN  UINT8          SerDesNumLanes,
    IN  SERDES_CONFIG  *Config
    )
  {
    UINT8 Count;
  
    while (Config->Protocol) {
      if (Config->Protocol == SerDesProtocol) {
        DEBUG ((DEBUG_INFO, "Protocol: 0x%x Matched with the one in Table\n", SerDesProtocol));
        break;
      }
      Config++;
    }
  
    if (!Config->Protocol) {
      return EFI_NOT_FOUND;
    }
  
    for (Count = 0; Count < SerDesNumLanes; Count++) {
      if (Config->SerDesLane[Count] != 0) {
        return EFI_SUCCESS;
      }
    }
  
    return EFI_NOT_FOUND;
  }
  
  /**
    Get Lane protocol on provided SerDes Lane and execute callback function.
  
    @param  SerDes                  SerDes number.
    @param  SerDesProtocol          SerDes protocol number.
    @param  SerDesNumLanes          Number of SerDes Lanes.
    @param  SerDesMaxProtocol       Max SerDes protocol number.
    @param  Config                  SerDes Configuration.
    @param  SerDesLaneProbeCallback Pointer Callback function to be called for Lane protocol
    @param  Arg                     Pointer to Arguments to be passed to callback function.
  **/
  VOID
  SerDesInstanceProbeLanes (
    IN  UINT32                      SerDes,
    IN  UINT32                      SerDesProtocol,
    IN  UINT8                       SerDesNumLanes,
    IN  UINT32                      SerDesMaxProtocol,
    IN  SERDES_CONFIG               *Config,
    IN  SERDES_PROBE_LANES_CALLBACK SerDesLaneProbeCallback,
    IN  VOID                        *Arg
    )
  {
    INT8    Lane;
    UINT32  LaneProtocol;
  
    // Invoke callback for all lanes in the SerDes instance:
    for (Lane = 0; Lane < SerDesNumLanes; Lane++) {
      LaneProtocol = GetSerDesProtocol (SerDes, SerDesProtocol, Lane, SerDesMaxProtocol, Config);
      ASSERT (LaneProtocol < SerDesMaxProtocol);
      if (LaneProtocol != 0x0) {
        SerDesLaneProbeCallback (LaneProtocol, Arg);
      }
    }
  }
  
  /**
    Function to fill SerDes map information.
  
    @param  SerDes              SerDes number.
    @param  SerDesProtocol      SerDes protocol number.
    @param  SerDesNumLanes      Number of SerDes Lanes.
    @param  SerDesMaxProtocol   Max SerDes protocol number.
    @param  Config              SerDes Configuration.
    @param  SerDesProtocolMap   Output SerDes protocol map of enabled devices.
  
  **/
  EFI_STATUS
  GetSerDesMap (
    IN  UINT32                    SerDes,
    IN  UINT32                    SerDesProtocol,
    IN  UINT8                     SerDesNumLanes,
    IN  UINT32                    SerDesMaxProtocol,
    IN  SERDES_CONFIG             *Config,
    OUT UINT64                    *SerDesProtocolMap
    )
  {
    INTN                   Lane;
    EFI_STATUS             Status;
    UINT32                 LaneProtocol;
  
    Status = IsSerDesProtocolValid (SerDes, SerDesProtocol, SerDesNumLanes, Config);
    if (EFI_ERROR (Status)) {
      DEBUG ((DEBUG_ERROR, "%a: SERDES%d[PRTCL] = 0x%x is not valid, Status = %r \n",
              __FUNCTION__, SerDes + 1, SerDesProtocol, Status));
      return Status;
    }
  
    for (Lane = 0; Lane < SerDesNumLanes; Lane++) {
      LaneProtocol = GetSerDesProtocol (SerDes, SerDesProtocol, Lane, SerDesMaxProtocol, Config);
      if (LaneProtocol >= SerDesMaxProtocol) {
        DEBUG ((DEBUG_ERROR, "Unknown SerDes lane protocol %d\n", LaneProtocol));
        return EFI_NO_MAPPING;
      }
      *SerDesProtocolMap |= (BIT0 << (LaneProtocol));
    }
  
    return EFI_SUCCESS;
  }
  