/* $Id: xemac_options.c,v 1.1 2003/09/26 22:04:52 moleres Exp $ */
/******************************************************************************
*
*       XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
*       AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
*       SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
*       OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
*       APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
*       THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
*       AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
*       FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
*       WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
*       IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
*       REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
*       INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*       FOR A PARTICULAR PURPOSE.
*
*       (c) Copyright 2003 Xilinx Inc.
*       All rights reserved.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xemac_options.c
*
* Functions in this file handle configuration of the XEmac driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---- -------- -----------------------------------------------
* 1.00a rpm  07/31/01 First release
* 1.00b rpm  02/20/02 Repartitioned files and functions
* 1.00c rpm  12/05/02 New version includes support for simple DMA
* 1.00d rpm  09/26/03 New version includes support PLB Ethernet and v2.00a of
*                     the packet fifo driver.
* </pre>
*
******************************************************************************/

/***************************** Include Files *********************************/

#include "xbasic_types.h"
#include "xemac_i.h"
#include "xio.h"

/************************** Constant Definitions *****************************/

#define XEM_MAX_IFG         32      /* Maximum Interframe gap value */

/**************************** Type Definitions *******************************/


/***************** Macros (Inline Functions) Definitions *********************/


/************************** Function Prototypes ******************************/


/************************** Variable Definitions *****************************/

/*
 * A table of options and masks. This table maps the user-visible options with
 * the control register masks. It is used in Set/GetOptions as an alternative
 * to a series of if/else pairs. Note that the polled options does not have a
 * corresponding entry in the control register, so it does not exist in the
 * table.
 */
typedef struct
{
    Xuint32 Option;
    Xuint32 Mask;
} OptionMap;

static OptionMap OptionsTable[] =
{
        {XEM_UNICAST_OPTION, XEM_ECR_UNICAST_ENABLE_MASK},
        {XEM_BROADCAST_OPTION, XEM_ECR_BROAD_ENABLE_MASK},
        {XEM_PROMISC_OPTION, XEM_ECR_PROMISC_ENABLE_MASK},
        {XEM_FDUPLEX_OPTION, XEM_ECR_FULL_DUPLEX_MASK},
        {XEM_LOOPBACK_OPTION, XEM_ECR_LOOPBACK_MASK},
        {XEM_MULTICAST_OPTION, XEM_ECR_MULTI_ENABLE_MASK},
        {XEM_FLOW_CONTROL_OPTION, XEM_ECR_PAUSE_FRAME_MASK},
        {XEM_INSERT_PAD_OPTION, XEM_ECR_XMIT_PAD_ENABLE_MASK},
        {XEM_INSERT_FCS_OPTION, XEM_ECR_XMIT_FCS_ENABLE_MASK},
        {XEM_INSERT_ADDR_OPTION, XEM_ECR_XMIT_ADDR_INSERT_MASK},
        {XEM_OVWRT_ADDR_OPTION, XEM_ECR_XMIT_ADDR_OVWRT_MASK},
        {XEM_STRIP_PAD_FCS_OPTION, XEM_ECR_RECV_STRIP_ENABLE_MASK}
};

#define XEM_NUM_OPTIONS     (sizeof(OptionsTable) / sizeof(OptionMap))

/*****************************************************************************/
/**
*
* Set Ethernet driver/device options.  The device must be stopped before
* calling this function.  The options are contained within a bit-mask with each
* bit representing an option (i.e., you can OR the options together). A one (1)
* in the bit-mask turns an option on, and a zero (0) turns the option off.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
* @param OptionsFlag is a bit-mask representing the Ethernet options to turn on
*        or off. See xemac.h for a description of the available options.
*
* @return
*
* - XST_SUCCESS if the options were set successfully
* - XST_DEVICE_IS_STARTED if the device has not yet been stopped
*
* @note
*
* This function is not thread-safe and makes use of internal resources that are
* shared between the Start, Stop, and SetOptions functions, so if one task
* might be setting device options while another is trying to start the device,
* protection of this shared data (typically using a semaphore) is required.
*
******************************************************************************/
XStatus XEmac_SetOptions(XEmac *InstancePtr, Xuint32 OptionsFlag)
{
    Xuint32 ControlReg;
    int Index;

    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED)
    {
        return XST_DEVICE_IS_STARTED;
    }

    ControlReg = XIo_In32(InstancePtr->BaseAddress + XEM_ECR_OFFSET);

    /*
     * Loop through the options table, turning the option on or off
     * depending on whether the bit is set in the incoming options flag.
     */
    for (Index = 0; Index < XEM_NUM_OPTIONS; Index++)
    {
        if (OptionsFlag & OptionsTable[Index].Option)
        {
            ControlReg |= OptionsTable[Index].Mask;     /* turn it on */
        }
        else
        {
            ControlReg &= ~OptionsTable[Index].Mask;    /* turn it off */
        }
    }

    /*
     * TODO: need to validate addr-overwrite only if addr-insert?
     */

    /*
     * Now write the control register. Leave it to the upper layers
     * to restart the device.
     */
    XIo_Out32(InstancePtr->BaseAddress + XEM_ECR_OFFSET, ControlReg);

    /*
     * Check the polled option
     */
    if (OptionsFlag & XEM_POLLED_OPTION)
    {
        InstancePtr->IsPolled = XTRUE;
    }
    else
    {
        InstancePtr->IsPolled = XFALSE;
    }

    return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* Get Ethernet driver/device options. The 32-bit value returned is a bit-mask
* representing the options.  A one (1) in the bit-mask means the option is on,
* and a zero (0) means the option is off.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
*
* @return
*
* The 32-bit value of the Ethernet options. The value is a bit-mask
* representing all options that are currently enabled. See xemac.h for a
* description of the available options.
*
* @note
*
* None.
*
******************************************************************************/
Xuint32 XEmac_GetOptions(XEmac *InstancePtr)
{
    Xuint32 OptionsFlag = 0;
    Xuint32 ControlReg;
    int Index;

    XASSERT_NONVOID(InstancePtr != XNULL);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    /*
     * Get the control register to determine which options are currently set.
     */
    ControlReg = XIo_In32(InstancePtr->BaseAddress + XEM_ECR_OFFSET);

    /*
     * Loop through the options table to determine which options are set
     */
    for (Index = 0; Index < XEM_NUM_OPTIONS; Index++)
    {
        if (ControlReg & OptionsTable[Index].Mask)
        {
            OptionsFlag |= OptionsTable[Index].Option;
        }
    }

    if (InstancePtr->IsPolled)
    {
        OptionsFlag |= XEM_POLLED_OPTION;
    }

    return OptionsFlag;
}


/*****************************************************************************/
/**
*
* Set the Interframe Gap (IFG), which is the time the MAC delays between
* transmitting frames.  There are two parts required.  The total interframe gap
* is the total of the two parts.  The values provided for the Part1 and Part2
* parameters are multiplied by 4 to obtain the bit-time interval. The first
* part should be the first 2/3 of the total interframe gap. The MAC will reset
* the interframe gap timer if carrier sense becomes true during the period
* defined by interframe gap Part1. Part1 may be shorter than 2/3 the total and
* can be as small as zero. The second part should be the last 1/3 of the total
* interframe gap, but can be as large as the total interframe gap. The MAC
* will not reset the interframe gap timer if carrier sense becomes true during
* the period defined by interframe gap Part2.
*
* The device must be stopped before setting the interframe gap.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
* @param Part1 is the interframe gap part 1 (which will be multiplied by 4 to
*        get the bit-time interval).
* @param Part2 is the interframe gap part 2 (which will be multiplied by 4 to
*        get the bit-time interval).
*
* @return
*
* - XST_SUCCESS if the interframe gap was set successfully
* - XST_DEVICE_IS_STARTED if the device has not been stopped
*
* @note
*
* None.
*
******************************************************************************/
XStatus XEmac_SetInterframeGap(XEmac *InstancePtr, Xuint8 Part1,
                               Xuint8 Part2)
{
    Xuint32 Ifg;

    XASSERT_NONVOID(InstancePtr != NULL);
    XASSERT_NONVOID(Part1 < XEM_MAX_IFG);
    XASSERT_NONVOID(Part2 < XEM_MAX_IFG);
    XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    /*
     * Be sure device has been stopped
     */
    if (InstancePtr->IsStarted == XCOMPONENT_IS_STARTED)
    {
        return XST_DEVICE_IS_STARTED;
    }

    Ifg = Part1 << XEM_IFGP_PART1_SHIFT;
    Ifg |= (Part2 << XEM_IFGP_PART2_SHIFT);
    XIo_Out32(InstancePtr->BaseAddress + XEM_IFGP_OFFSET, Ifg);

    return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* Get the interframe gap, parts 1 and 2. See the description of interframe gap
* above in XEmac_SetInterframeGap().
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
* @param Part1Ptr is a pointer to an 8-bit buffer into which the interframe gap
*        part 1 value will be copied.
* @param Part2Ptr is a pointer to an 8-bit buffer into which the interframe gap
*        part 2 value will be copied.
*
* @return
*
* None. The values of the interframe gap parts are copied into the
* output parameters.
*
******************************************************************************/
void XEmac_GetInterframeGap(XEmac *InstancePtr, Xuint8 *Part1Ptr,
                            Xuint8 *Part2Ptr)
{
    Xuint32 Ifg;

    XASSERT_VOID(InstancePtr != XNULL);
    XASSERT_VOID(Part1Ptr != XNULL);
    XASSERT_VOID(Part2Ptr != XNULL);
    XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

    Ifg = XIo_In32(InstancePtr->BaseAddress + XEM_IFGP_OFFSET);
    *Part1Ptr = (Ifg & XEM_IFGP_PART1_MASK) >> XEM_IFGP_PART1_SHIFT;
    *Part2Ptr = (Ifg & XEM_IFGP_PART2_MASK) >> XEM_IFGP_PART2_SHIFT;
}

