blob: 37d4ac0f58d64501f5c42b9f6396f623ae2b54c3 [file] [log] [blame]
/******************************************************************************
*
* alt_bridge_manager.c - API for the Altera SoC FPGA bridge manager.
*
******************************************************************************/
/******************************************************************************
*
* Copyright 2013 Altera Corporation. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
******************************************************************************/
#include <stddef.h>
#include "alt_bridge_manager.h"
#include "alt_clock_manager.h"
#include "alt_fpga_manager.h"
#include "socal/hps.h"
#include "socal/socal.h"
#include "socal/alt_rstmgr.h"
/******************************************************************************/
ALT_STATUS_CODE alt_bridge_init(ALT_BRIDGE_t bridge,
alt_bridge_fpga_is_ready_t fpga_is_ready,
void* user_arg)
{
uint32_t bridge_reset_mask = 0;
// Validate the bridge parameter and set the appropriate bridge reset mask.
if (bridge == ALT_BRIDGE_LWH2F)
{
bridge_reset_mask = ALT_RSTMGR_BRGMODRST_LWH2F_SET_MSK;
}
else if (bridge == ALT_BRIDGE_H2F)
{
bridge_reset_mask = ALT_RSTMGR_BRGMODRST_H2F_SET_MSK;
}
else if (bridge == ALT_BRIDGE_F2H)
{
bridge_reset_mask = ALT_RSTMGR_BRGMODRST_F2H_SET_MSK;
}
else
{
// Invalid bridge argument specified.
return ALT_E_BAD_ARG;
}
// Place and hold the specified bridge in reset.
alt_setbits_word(ALT_RSTMGR_BRGMODRST_ADDR, bridge_reset_mask);
// Validate that bridge clock(s) are configured and stable. Perform the
// clock checks prior other validations that might depend on clocks being
// checked (e.g. FPGA manager dependency on ALT_CLK_L4_MP).
// l4_mp_clk is required for all bridges.
if (alt_clk_is_enabled(ALT_CLK_L4_MP) != ALT_E_TRUE)
{
return ALT_E_BAD_CLK;
}
// Although a stable l3_main_clk is required for H2F and F2H bridges, the
// l3_main_clk is not gated and it runs directly from the Main PLL C1 output
// so if this code is executing it effectively means that this clock is stable
// and hence there are no meaningful validation checks that software can perform
// on the ALT_CLK_L3_MAIN.
// lws2f_axi_clk is required for LWH2F bridge and clocks all LWH2F AXI transactions.
// s2f_axi_clk is required for H2F bridge and clocks all H2F AXI transactions.
// f2s_axi_clk is required for F2H bridge and clocks all F2H AXI transactions.
//
// NOTE: All of these clocks are sourced from the FPGA and provided to the HPS.
// The FPGA must be configured to drive these clocks. Beyond checking that
// the FPGA is configured, there are no HPS control and status mechanisms
// available to check the operational status of these clocks.
// Check that FPGA is powered on.
ALT_FPGA_STATE_t fpga_state = alt_fpga_state_get();
if (fpga_state == ALT_FPGA_STATE_POWER_OFF)
{
return ALT_E_FPGA_PWR_OFF;
}
// Check that FPGA has been configured and is in USER mode.
if (fpga_state != ALT_FPGA_STATE_USER_MODE)
{
return ALT_E_FPGA_NOT_USER_MODE;
}
// If specified, invoke user defined callback function to determine whether the
// FPGA is ready to commence bridge interface transactions. If no user defined
// callback function is specified then proceed on the assumption that the FPGA
// is ready to commence bridge transactions.
if (fpga_is_ready != NULL)
{
ALT_STATUS_CODE fpga_ready_status = fpga_is_ready(user_arg);
if (fpga_ready_status != ALT_E_SUCCESS)
{
// Return the value of the non successful status code as returned from
// the user defined callback function.
return fpga_ready_status;
}
}
// Release the bridge from reset.
alt_clrbits_word(ALT_RSTMGR_BRGMODRST_ADDR, bridge_reset_mask);
return ALT_E_SUCCESS;
}
/******************************************************************************/
ALT_STATUS_CODE alt_bridge_uninit(ALT_BRIDGE_t bridge,
alt_bridge_teardown_handshake_t handshake,
void* user_arg)
{
uint32_t bridge_reset_mask = 0;
// Validate the bridge parameter and set the appropriate bridge reset mask.
if (bridge == ALT_BRIDGE_LWH2F)
{
bridge_reset_mask = ALT_RSTMGR_BRGMODRST_LWH2F_SET_MSK;
}
else if (bridge == ALT_BRIDGE_H2F)
{
bridge_reset_mask = ALT_RSTMGR_BRGMODRST_H2F_SET_MSK;
}
else if (bridge == ALT_BRIDGE_F2H)
{
bridge_reset_mask = ALT_RSTMGR_BRGMODRST_F2H_SET_MSK;
}
else
{
// Invalid bridge argument specified.
return ALT_E_BAD_ARG;
}
if ((alt_read_word(ALT_RSTMGR_BRGMODRST_ADDR) & bridge_reset_mask) == bridge_reset_mask)
{
// The bridge is already in reset and therefore considered uninitialized.
return ALT_E_SUCCESS;
}
// If specified, invoke user defined callback function to perform the tear-down
// handshake notification protocol with the FPGA. If no user defined callback
// function is specified then proceed without performing any tear-down handshake
// notification protocol with the FPGA.
if (handshake != NULL)
{
ALT_STATUS_CODE handshake_status = handshake(user_arg);
if (handshake_status != ALT_E_SUCCESS)
{
// Return the value of the non successful status code as returned from
// the user defined callback function.
return handshake_status;
}
}
// Place and hold the bridge in reset.
alt_setbits_word(ALT_RSTMGR_BRGMODRST_ADDR, bridge_reset_mask);
return ALT_E_SUCCESS;
}
/******************************************************************************/