Hi team,
I can't see the sample code for TIDA-010010.
Could you please share phy_init.c file?
Best regards,
Iwata Etsuji
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi team,
I can't see the sample code for TIDA-010010.
Could you please share phy_init.c file?
Best regards,
Iwata Etsuji
Hi Etsuji-san,
Please find attached the phy_init.c file which was used for TIDA-010010.
Regards,
Thomas
#include <ti/csl/soc.h>
#include <ti/csl/hw_types.h>
#include <ti/csl/csl_timer.h>
#include <ti/csl/arch/csl_arch.h>
#include <ti/csl/csl_i2c.h>
#include <ti/csl/cslr.h>
#include <ti/csl/soc/am572x/src/cslr_control_core_pad_io.h>
#include <ti/drv/pm/pmhal.h>
#include <ti/drv/pm/pmlib.h>
#include <ti/drv/pm/Power.h>
#include <ti/drv/pm/PowerExtended.h>
#include <ti/drv/pm/PowerDevice.h>
#include <ti/drv/pm/include/pmlib_boardconfig.h>
#include <ti/drv/pm/include/prcm/pmhal_i2cComm.h>
#include <ti/drv/pm/include/prcm/pmhal_pmicComm.h>
#if defined (SOC_TDA2EX) || defined (SOC_DRA72x)
#include <ti/drv/pm/include/pmic/pmhal_tps65917.h>
#elif defined (SOC_TDA3XX) || defined (SOC_DRA78x)
#include <ti/drv/pm/include/pmic/pmhal_tps65917.h>
#include <ti/drv/pm/include/pmic/pmhal_tps659039.h>
#include <ti/drv/pm/include/pmic/pmhal_lp8731.h>
#elif defined(SOC_AM574x) || defined (SOC_AM572x) || defined (SOC_AM571x)
#include <ti/drv/pm/include/pmic/pmhal_tps659037.h>
#else
#include <ti/drv/pm/include/pmic/pmhal_tps659039.h>
#endif
#include <ti/drv/gpio/GPIO.h>
#include <ti/drv/gpio/soc/GPIO_v1.h>
#include <ti/board/src/evmAM572x/include/evmam572x_pinmux.h>
#include <ti/sysbios/knl/Clock.h>
/* -------------------------------------------------------------------------- */
/* Internal Function Definitions */
/* -------------------------------------------------------------------------- */
#if defined (__ARM_ARCH_7A__)
PowerDevice_Cfg_t PowerDevice_config __attribute__ ((section (".noinit")));
#elif defined (_TMS320C6X)
#pragma DATA_SECTION(PowerDevice_config, ".noinit")
PowerDevice_Cfg_t PowerDevice_config;
#else
#pragma NOINIT(PowerDevice_config)
PowerDevice_Cfg_t PowerDevice_config;
#endif
/** I2C System Clock - PER_96M_CLK: 96 MHz */
#define PM_TEST_UTILS_I2C_SYSTEM_CLOCK (96000000U)
/** I2C Internal Clock - 9.6 MHz , Fast Mode of Communication is
* is used here. A pre-scaler of 23 would be calculated here. Refer
* TRM for details on the different I2C modes.
*/
#define PM_TEST_UTILS_I2C_INTERNAL_CLOCK (9600000U)
/** I2C Output Clock - 400 KHz, This complies with the Fast Mode
* of the I2C operation of 100 Kbps.
*/
#define PM_TEST_UTILS_I2C_OUTPUT_CLOCK (400000U)
/**
* When checking for I2C IRQSTATUS setting this count is used to
* repeatedly check the status. This number is empirically derived.
*/
#define PM_TEST_UTILS_I2C_TIMEOUT_COUNT (4000U)
/** Write Flag used when checking for the transfer status. */
#define PM_TEST_UTILS_I2C_WRITE (1U)
/** Read Flag used when checking for the transfer status. */
#define PM_TEST_UTILS_I2C_READ (2U)
/**
* \brief This function performs the I2C initialization to talk to PMIC.
*
* \param None.
*
* \retval None.
*/
static int32_t PmTestUtilsI2cInit(void);
/**
* \brief This function reads a byte from the PMIC via I2C
*
* \param i2cNum Instance Id of the I2C. 1 - for I2C1, 2 - for I2C2
* \param i2cDevAddr I2C Slave address for the PMIC
* \param regAddr Pointer to the register address which is to be read.
* \param regValue Pointer to the location where the read value will be
* placed.
* \param numRegs Number of registers to be read.
*
* \retval status Pass or fail value of the operations. STW_SOK - If Pass
* STW_EFAIL - If Fail
*/
static int32_t PmTestUtilsI2cReadByte(uint32_t i2cNum, uint32_t i2cDevAddr,
const uint8_t *regAddr,
uint8_t *regValue,
uint32_t numRegs);
/**
* \brief This function writes a byte of data to the register of PMIC via I2C
*
* \param i2cNum Instance Id of the I2C. 1 - for I2C1, 2 - for I2C2
* \param i2cDevAddr I2C Slave address for the PMIC
* \param regAddr Pointer to the register address which is to be written.
* \param regValue Pointer to the location where the write value will be
* placed.
* \param numRegs Number of registers to be written.
*
* \retval status Pass or fail value of the operations. STW_SOK - If Pass
* STW_EFAIL - If Fail
*/
static int32_t PmTestUtilsI2cWriteByte(uint32_t i2cNum, uint32_t i2cDevAddr,
const uint8_t *regAddr,
const uint8_t *regValue,
uint32_t numRegs);
/**
* \brief Poll for Bus Busy and return when bus is not busy or timed out.
*
* \param i2cNum The I2C number used on the board to connect to the
* desired PMIC.
*
* \retval status Pass or fail value of the operations. STW_SOK - If Pass
* STW_EFAIL - If Fail
*/
static int32_t PmTestUtilsI2cWaitForBB(uint32_t i2cNum);
/**
* \brief Poll for the given flags and return when any of the flags is set or
* timed out.
*
* \param i2cNum The I2C number used on the board to connect to the
* desired PMIC.
* \param flags Flag to be waited for.
*
* \retval status Pass or fail value of the operations. STW_SOK - If Pass
* STW_EFAIL - If Fail
*/
static int32_t PmTestUtilsI2cWaitForFlags(uint32_t i2cNum, uint32_t flags);
/**
* \brief Write the given number of bytes to the given slave address.
*
* \param i2cNum The I2C number used on the board to connect to the
* desired PMIC.
* \param slaveAddr Address to which the data should be written.
* \param data Data to be written.
* \param count Number of Bytes to be written.
*
* \retval status Pass or fail value of the operations. STW_SOK - If Pass
* STW_EFAIL - If Fail
*/
static int32_t PmTestUtilsI2cWrite(uint32_t i2cNum,
uint8_t slaveAddr, const uint8_t data[],
uint8_t count);
/**
* \brief Read one byte from the given slave address.
*
* \param i2cNum The I2C number used on the board to connect to the
* desired PMIC.
* \param slaveAddr Address to which the data should be written.
* \param value Data to be read is returned.
*
* \retval status Pass or fail value of the operations. STW_SOK - If Pass
* STW_EFAIL - If Fail
*/
static int32_t PmTestUtilsI2cRead(uint32_t i2cNum,
uint8_t slaveAddr,
uint8_t *value);
/**
* \brief Check the status of the transfer and handle the error conditions.
*
* \param i2cNum The I2C number used on the board to connect to the
* desired PMIC.
* \param xfr Transfer Type. Can be any one of PM_TEST_UTILS_I2C_WRITE or
* PM_TEST_UTILS_I2C_READ.
*
* \retval status Pass or fail value of the operations. STW_SOK - If Pass
* STW_EFAIL - If Fail
*/
static int32_t PmTestUtilsI2cCheckXfrStatus(uint32_t i2cNum, uint32_t xfr);
static void delay(uint32_t delay)
{
volatile uint32_t i;
for (i = 0; i < (1000 * delay); ++i) ;
}
/*
* Table containing pointers to the functions to program I2C to talk to PMIC IC.
*/
static const pmhalI2cCommOperations_t gPmicI2cfunc = {
&PmTestUtilsI2cInit,
&PmTestUtilsI2cReadByte,
&PmTestUtilsI2cWriteByte,
NULL,
NULL
};
/* GPIO Driver board specific pin configuration structure */
GPIO_PinConfig gpioPinConfigs[] =
{
/* Output pin : AM572x EVM PHY1 Reset */
GPIO_DEVICE_CONFIG(5, 17) |
GPIO_CFG_OUTPUT ,
/* Output pin : AM572x EVM PHY2 Reset */
GPIO_DEVICE_CONFIG(3, 29) |
GPIO_CFG_OUTPUT
};
/* GPIO Driver call back functions */
GPIO_CallbackFxn gpioCallbackFunctions[] = {
NULL,
NULL
};
/* GPIO Driver configuration structure */
GPIO_v1_Config GPIO_v1_config = {
gpioPinConfigs,
gpioCallbackFunctions,
sizeof(gpioPinConfigs) / sizeof(GPIO_PinConfig),
sizeof(gpioCallbackFunctions) / sizeof(GPIO_CallbackFxn),
0,
};
void dp83867_reset_sequence(void)
{
uint32_t regVal = 0;
/* configure GPIOs as outputs*/
/* pinmux */
/* AM572x EVM GPIO5_17 RESET PHY1 */
CSL_FINS(regVal, CONTROL_CORE_PAD_IO_PAD_RMII_MHZ_50_CLK_RMII_MHZ_50_CLK_MUXMODE, 0xEU);
((CSL_padRegsOvly) CSL_MPU_CORE_PAD_IO_REGISTERS_REGS)->PAD_RMII_MHZ_50_CLK = regVal;
/* AM572x EVM GPIO3_29 RESET PHY2 */
CSL_FINS(regVal, CONTROL_CORE_PAD_IO_PAD_VIN2A_DE0_VIN2A_DE0_MUXMODE, 0xEU);
((CSL_padRegsOvly) CSL_MPU_CORE_PAD_IO_REGISTERS_REGS)->PAD_VIN2A_DE0 = regVal;
/* configure GPIO */
GPIO_init();
/* Reset sequence: 1us reset asserted; then first PHY needs to wait for 201 ms before second PHY comes out of reset */
GPIO_write(0, 0); /* set GPIO5_17 to low */
GPIO_write(1, 0); /* set GPIO3_29 to low */
delay(1); /* data sheet requires >1us; Note: delay(1*125)=1ms --> 1-> 8us*/
GPIO_write(0, 1); /* set GPIO5_17 to high */
delay(201*125); /* 201ms */
GPIO_write(1, 1); /* set GPIO3_29 to high */
}
void dp83867_pmic_init(void)
{
const pmhalPmicOperations_t *pmicOps;
uint32_t retVal;
/* Register the I2C functions with the PMIC Communication to ensure the
* PMIC can be communicated with I2C driver
*/
PMHALI2CCommRegister(&gPmicI2cfunc);
pmicOps = PMHALTps659037GetPMICOps();
retVal = PMHALPmicRegister(pmicOps);
if(retVal != 0)
return;
/* enable the PHY voltage supplies */
PMHALPmicSetRegulatorVoltage(PMHAL_PRCM_PMIC_REGULATOR_EPHY2V5,2500,PM_TIMEOUT_INFINITE,FALSE);
PMHALPmicSetRegulatorVoltage(PMHAL_PRCM_PMIC_REGULATOR_EPHY1V0,1000,PM_TIMEOUT_INFINITE,FALSE);
PMHALPmicEnableRegulator(PMHAL_PRCM_PMIC_REGULATOR_EPHY2V5);
PMHALPmicEnableRegulator(PMHAL_PRCM_PMIC_REGULATOR_EPHY1V0);
// Example to read out the configured PMIC voltage
//PMHALPmicGetRegulatorVoltage(PMHAL_PRCM_PMIC_REGULATOR_EPHY2V5, &retVal);
//PMHALPmicGetRegulatorVoltage(PMHAL_PRCM_PMIC_REGULATOR_EPHY1V0, &retVal);
}
void dp83867_register_init(void)
{
// register dump
ENETPHY_UserAccessWrite();
}
static int32_t PmTestUtilsI2cInit(void)
{
int32_t status = STW_SOK;
uint32_t timeout;
uint32_t baseAddr = SOC_I2C1_BASE;
#if defined (SOC_TDA3XX) || defined (SOC_DRA78x)
/* Force Wake-up clock domain L4PER1 */
PMHALCMSetCdClockMode(PMHAL_PRCM_CD_L4PER1,
PMHAL_PRCM_CD_CLKTRNMODES_SW_WAKEUP,
PM_TIMEOUT_NOWAIT);
#else
/* Force Wake-up clock domain L4PER */
PMHALCMSetCdClockMode(PMHAL_PRCM_CD_L4PER,
PMHAL_PRCM_CD_CLKTRNMODES_SW_WAKEUP,
PM_TIMEOUT_NOWAIT);
#endif
/* Enable I2C1 for PMIC Communication */
PMHALModuleModeSet(PMHAL_PRCM_MOD_I2C1,
PMHAL_PRCM_MODULE_MODE_ENABLED,
PM_TIMEOUT_INFINITE);
/*
* Do a soft reset so we can clear any incorrect state and
* configure to suit the PMIC communication.
*/
I2CSoftReset(baseAddr);
/*
* Ensure that the reset is completed. The RDONE bit is set
* only when the I2C is enabled, so enable I2C before
* checking for the reset completion.
*/
I2CMasterEnable(baseAddr);
timeout = 50U; /* Approximately 50ms */
while ((I2CSystemStatusGet(baseAddr) !=
I2C_SYSS_RDONE_RSTCOMP)
&& (timeout > 0))
{
PMUtilsMinDelayMS((uint32_t) 1U);
timeout--;
}
if (timeout == 0)
{
status = STW_EFAIL;
}
if (status == STW_SOK)
{
/* Disable I2C so we can configure for the PMIC communication. */
I2CMasterEnable(baseAddr);
/* Configure the I2C BUS clock frequency (I2C_SCL). */
I2CMasterInitExpClk(baseAddr,
PM_TEST_UTILS_I2C_SYSTEM_CLOCK,
PM_TEST_UTILS_I2C_INTERNAL_CLOCK,
PM_TEST_UTILS_I2C_OUTPUT_CLOCK);
/*
* The PMIC communication is always as a master so we don't have
* to configure the I2C own address. However, it doesn't hurt.
*/
I2COwnAddressSet(baseAddr, 0,
I2C_OWN_ADDR_0);
/*
* Make sure the I2C is not in Forced Idle Mode by setting it to No
* Idle mode.
*/
I2CSyscInit(baseAddr,
(uint32_t) (I2C_AUTOIDLE_DISABLE |
I2C_CUT_OFF_BOTH_CLK |
I2C_ENAWAKEUP_DISABLE |
I2C_NO_IDLE_MODE));
/*
* Configure the I2C:
* Select Fast/Standard Mode
* Select normal mode (vs. start byte mode)
* Select 7-bit slave address mode
*
* Note that this API writes the 32-bit value passed to the I2C_CON
* register; the config bits not mentioned below is set to zero.
*/
I2CConfig(baseAddr, I2C_CFG_N0RMAL_MODE |
I2C_CFG_7BIT_SLAVE_ADDR |
I2C_OPMODE_FAST_STAND_MODE);
/* PMIC Comm uses polling mode; disable all the interrupts. */
I2CMasterIntDisableEx(baseAddr, I2C_INT_ALL);
/*
* Bypass the Tx/Rx FIFO. For PRCM access we always read one byte
* at a time so FIFO is bypassed.
*/
I2CFIFOThresholdConfig(baseAddr,
0, I2C_TX_MODE);
I2CFIFOThresholdConfig(baseAddr,
0, I2C_RX_MODE);
I2CFIFOClear(baseAddr, I2C_TX_MODE);
I2CFIFOClear(baseAddr, I2C_RX_MODE);
/* Enable I2C module. */
I2CMasterEnable(baseAddr);
/*
* This is required to ensure that the I2C communication continues
* even if A15 (the master core) is debug halted on a breakpoint.
*/
I2CMasterEnableFreeRun(baseAddr);
}
/* Clear status register */
I2CMasterIntClearEx(baseAddr, I2C_INT_ALL);
return status;
}
static int32_t PmTestUtilsI2cReadByte(uint32_t i2cNum, uint32_t i2cDevAddr,
const uint8_t *regAddr,
uint8_t *regValue,
uint32_t numRegs)
{
int32_t status = STW_SOK;
status = PmTestUtilsI2cWrite(i2cNum, i2cDevAddr, regAddr, 1U);
/* Then read the value sent by the slave. */
if (status == STW_SOK)
{
status = PmTestUtilsI2cRead(i2cNum, i2cDevAddr, regValue);
}
else
{
*regValue = 0U;
}
return status;
}
static int32_t PmTestUtilsI2cWriteByte(uint32_t i2cNum, uint32_t i2cDevAddr,
const uint8_t *regAddr,
const uint8_t *regValue,
uint32_t numRegs)
{
uint8_t data[2];
uint8_t count = (uint8_t) 2U;
int32_t status = STW_SOK;
uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
data[0] = *regAddr;
data[1] = *regValue;
status = PmTestUtilsI2cWrite(i2cNum, i2cDevAddr, data, count);
if (status == STW_SOK)
{
/*
* Generate a stop condition and ensure the
* bus is free before returning.
*/
I2CMasterStop(baseAddress);
status = PmTestUtilsI2cWaitForFlags(i2cNum,
I2C_INT_BUS_FREE |
I2C_INT_ADRR_READY_ACESS);
I2CFlushFifo(baseAddress);
/* Clear the data count and all the flags. */
I2CMasterIntClearEx(baseAddress, I2C_INT_ALL);
I2CSetDataCount(baseAddress, (uint32_t) 0U);
}
return status;
}
static int32_t PmTestUtilsI2cRead(uint32_t i2cNum,
uint8_t slaveAddr,
uint8_t *value)
{
int32_t status = STW_SOK;
uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
/* Set the slave address */
I2CMasterSlaveAddrSet(baseAddress,
(uint32_t) slaveAddr);
/* Configure to read 1 data word from the PMIC register. */
I2CSetDataCount(baseAddress, (uint32_t) 1U);
/*
* Configure i2c as master-receive and enable.
* Make sure stop condition is generated after the transaction.
*/
I2CMasterControl(baseAddress,
(uint32_t) (I2C_CFG_MST_RX | I2C_CFG_START | I2C_CFG_STOP));
/* Read the data if the data is ready. */
status = PmTestUtilsI2cCheckXfrStatus(i2cNum,
(uint32_t) PM_TEST_UTILS_I2C_READ);
if (status == STW_SOK)
{
*value = I2CMasterDataGet(baseAddress);
}
else
{
*value = 0U;
}
/* Wait for I2C access ready before returning. */
if (status == STW_SOK)
{
uint32_t flags = I2C_INT_ADRR_READY_ACESS |
I2C_INT_BUS_FREE;
status = PmTestUtilsI2cWaitForFlags(i2cNum, flags);
}
/* Clear the status of the I2C */
I2CFlushFifo(baseAddress);
I2CMasterIntClearEx(baseAddress, I2C_INT_ALL);
I2CSetDataCount(baseAddress, (uint32_t) 0U);
return status;
}
static int32_t PmTestUtilsI2cWrite(uint32_t i2cNum,
uint8_t slaveAddr, const uint8_t data[],
uint8_t count)
{
int32_t status = STW_SOK;
uint32_t rawSt;
uint8_t i;
uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
/*
* Poll the BUS BUSY bit to ensure the bus is not busy before initiating
* the transaction on the bus.
*/
status = PmTestUtilsI2cWaitForBB(i2cNum);
if (status == STW_SOK)
{
/* Set the slave address */
I2CMasterSlaveAddrSet(baseAddress,
(uint32_t) slaveAddr);
/* Configure to send 'count' data words */
I2CSetDataCount(baseAddress, (uint32_t) count);
/*
* Configure i2c as master-transmitter, enable and set start condition.
* Stop condition is NOT generated as this could be a part of write
* followed by read (combined format).
*/
I2CMasterControl(baseAddress,
I2C_CFG_MST_TX | I2C_CFG_START);
/* Transmit 'count' bytes. */
for (i = 0; ((i < count) && (status == STW_SOK)); i++)
{
/*
* Check the status to see if the data can be transferred and
* send data.
*/
status = PmTestUtilsI2cCheckXfrStatus(
i2cNum,
(uint32_t)
PM_TEST_UTILS_I2C_WRITE);
if (status == PM_SUCCESS)
{
I2CMasterDataPut(baseAddress, data[i]);
}
/* Clear XRDY flags */
rawSt = I2CMasterIntRawStatus(baseAddress);
I2CMasterIntClearEx(baseAddress,
rawSt & I2C_INT_TRANSMIT_READY);
}
/*
* Once we complete writing the 'count' bytes, wait for the
* ARDY flag to be set. This flag indicates that the I2C
* is access ready for next transmission. ARDY can also be
* set if we received NACK so ensure it is not the case.
*/
if (status == STW_SOK)
{
status = PmTestUtilsI2cWaitForFlags(i2cNum,
I2C_INT_ADRR_READY_ACESS);
if (status == STW_SOK)
{
rawSt = I2CMasterIntRawStatus(baseAddress);
if ((rawSt & I2C_INT_NO_ACK) != 0)
{
status = STW_EFAIL;
/* Clear the NACK flag. */
I2CMasterIntClearEx(baseAddress,
rawSt & I2C_INT_NO_ACK);
}
/* Clear the ARDY flag. */
I2CMasterIntClearEx(baseAddress,
rawSt & I2C_INT_ADRR_READY_ACESS);
}
}
}
return status;
}
static int32_t PmTestUtilsI2cWaitForFlags(uint32_t i2cNum, uint32_t flags)
{
int32_t status = STW_SOK;
uint32_t timeout;
uint32_t rawSt;
uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
timeout = PM_TEST_UTILS_I2C_TIMEOUT_COUNT;
rawSt = I2CMasterIntRawStatus(baseAddress);
while (((rawSt & flags) == 0) && (timeout > 0U))
{
rawSt = I2CMasterIntRawStatus(baseAddress);
timeout--;
}
if (timeout == 0U)
{
status = STW_EFAIL;
}
return status;
}
static int32_t PmTestUtilsI2cWaitForBB(uint32_t i2cNum)
{
int32_t status = STW_SOK;
uint32_t timeout;
uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
/*
* Clear all current interrupts first.
*/
I2CMasterIntClearEx(baseAddress, I2C_INT_ALL);
/*
* Poll the BUS BUSY bit to ensure the bus is not busy before initiating
* the transaction on the bus.
*/
for (timeout = PM_TEST_UTILS_I2C_TIMEOUT_COUNT; timeout > 0U; --timeout)
{
if (I2CMasterBusBusy(baseAddress) == 0)
{
break;
}
I2CMasterIntClearEx(baseAddress, I2C_INT_BUS_BUSY);
}
if (timeout == 0U)
{
status = STW_EFAIL;
}
/*
* Clear all current interrupts.
*/
I2CMasterIntClearEx(baseAddress, I2C_INT_ALL);
return status;
}
static int32_t PmTestUtilsI2cCheckXfrStatus(uint32_t i2cNum, uint32_t xfr)
{
int32_t status = STW_SOK;
uint32_t rawSt;
uint32_t flags = I2C_INT_ADRR_READY_ACESS | I2C_INT_NO_ACK |
I2C_INT_ARBITRATION_LOST;
uint32_t baseAddress = (i2cNum == 0U) ? (SOC_I2C1_BASE) : (SOC_I2C2_BASE);
if (xfr == PM_TEST_UTILS_I2C_WRITE)
{
flags |= I2C_INT_TRANSMIT_READY;
}
else if (xfr == PM_TEST_UTILS_I2C_READ)
{
flags |= I2C_INT_RECV_READY;
}
else
{
status = STW_EFAIL;
}
/*
* Wait for any of the following conditions to occur and
* handle them in the loop before transmitting data.
* NACK, AL, XRDY/RRDY, ARDY
*/
if (status == STW_SOK)
{
status = PmTestUtilsI2cWaitForFlags(i2cNum, flags);
}
if (status == STW_SOK)
{
rawSt = I2CMasterIntRawStatus(baseAddress);
/*
* When I2C is configured as master-transmitter and didn't
* receive ACK from slave, NACK condition is generated. The
* following could cause this situation:
* 1. No receiver is present on the bus with the transmitted
* address; board issue
* 2. Receiver is not ready to communicate with the master
* (probably a board/pmic device issue).
* 3. Receiver gets data or commands it doesn't understand
* (incorrect PMIC)
* 4. Receiver can't receive any more data bytes.
*
* NACK can be handled by a master by either generating a
* STOP condition or a repeated START condition to start
* a new transfer. In PMIC COMM we generate a STOP
* condition to abort the transfer and clear the NACK
* flag.
*
* I2C HW clears STT and STP bits in I2C_CON registers.
*/
if ((rawSt & I2C_INT_NO_ACK) != 0)
{
I2CMasterStop(baseAddress);
I2CMasterIntClearEx(baseAddress,
rawSt & I2C_INT_NO_ACK);
status = STW_EFAIL;
}
/*
* Arbitration loss occurs when multiple masters initiate
* transfer at the same time. Only one master wins and others
* loose the arbitration. The arbitration loss flag is set
* if this local host lost the arbitration. After an
* arbitration loss, the local host can continue to generate
* clock till the end of the byte transfer on the bus and
* must restart the transmission. Recovering from arbitration
* loss slightly complicates the code and this can be added
* if there is a need. At present we clear the flag and
* return error.
*
* When arbitration loss occurs, the I2C HW clears the
* STT, STP and MST bits. The local host switches to the
* slave mode.
*/
else if ((rawSt & I2C_INT_ARBITRATION_LOST) != 0)
{
I2CMasterIntClearEx(baseAddress,
rawSt & I2C_INT_ARBITRATION_LOST);
status = STW_EFAIL;
}
/*
* ARDY flag is set to indicate that the local host is access
* ready. We are in the middle of a data transfer and hence
* it is bad if we get ARDY flag set. For example, if we
* get NACKed, the ARDY flag is set in the middle of data
* transfer.
*/
else if ((rawSt & I2C_INT_ADRR_READY_ACESS) != 0)
{
I2CMasterIntClearEx(baseAddress,
rawSt & I2C_INT_ADRR_READY_ACESS);
status = STW_EFAIL;
}
/*
* XRDY flag is set when the TX FIFO is empty or the TX FIFO
* threshold is not reached. This means the local host can
* transmit now.
*
* RRDY flag is set when the RX FIFO is empty or the RX FIFO
* threshold is not reached. This means the local host can
* receive now.
*/
else if (((xfr == PM_TEST_UTILS_I2C_WRITE) &&
((rawSt & I2C_INT_TRANSMIT_READY) != 0)) ||
((xfr == PM_TEST_UTILS_I2C_READ) &&
((rawSt & I2C_INT_RECV_READY) != 0)))
{
/*
* Return success so that the caller can send/receive the data
* Note that the caller needs to clear the XRDY/RRDY flag as
* needed.
*/
status = STW_SOK;
}
else
{
/*
* We should not get here...
*/
status = STW_EFAIL;
}
}
return status;
}
Hi Etsuji-san,
Please find attached the file.
Regards,
Thomas
/**
* enet_phy.c
*
*
* Copyright (c) 2018 Texas Instruments Incorporated ALL RIGHTS RESERVED
*
*/
#include <stdio.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/knl/Idle.h>
#include <ti/sysbios/knl/Task.h>
#include <xdc/runtime/Timestamp.h>
#include <ti/csl/cslr_mdio.h>
#include <ti/csl/src/ip/mdio/V2/cslr_mdio.h>
#include <ti/csl/csl_mdio.h>
#include <ti/csl/src/ip/mdio/V2/csl_mdio.h>
#include <ti/csl/csl_mdioAux.h>
#include <ti/csl/src/ip/mdio/V2/csl_mdioAux.h>
#include <ti/board/src/evmAM572x/device/enet_phy.h>
/* UART Header files */
#include <ti/drv/uart/UART.h>
#include <ti/drv/uart/src/UART_osal.h>
#include <ti/drv/uart/UART_stdio.h>
#include "board_dpphy.h"
/* R A N D O M N U M B E R S U P P O R T */
#define COMMON_RANDOM_MAX 0xFFFFu
/* Enable the below macro to have prints on the IO Console */
//#define IO_CONSOLE
#ifndef IO_CONSOLE
#define ENET_PHY_log UART_printf
#else
#define ENET_PHY_log printf
#endif
static uint32_t RandomSeed = 1u;
static uint32_t cpswRandom(void)
{
RandomSeed = (RandomSeed * (1103515245u)) + (12345u);
return ((uint32_t) (RandomSeed/(65536u)) % (COMMON_RANDOM_MAX + 1u));
}
static uint32_t cpswRandomRange(uint32_t min, uint32_t max)
{
uint32_t iTmp;
iTmp = cpswRandom();
iTmp %= ((max - min) + 1u);
iTmp += min;
return(iTmp);
}
static void ENETPHY_DisablePhy(ENETPHY_Handle hPhyDev,uint32_t PhyNum);
static void ENETPHY_PhyTimeOut(ENETPHY_Handle hPhyDev);
static void ENETPHY_ResetPhy(ENETPHY_Handle hPhyDev,uint32_t PhyNum);
static void ENETPHY_SwRestartPhy(ENETPHY_Handle hPhyDev, uint32_t PhyNum);
static void ENETPHY_DefaultState (ENETPHY_Handle hPhyDev);
static void ENETPHY_FindingState (ENETPHY_Handle hPhyDev);
static void ENETPHY_FoundState (ENETPHY_Handle hPhyDev);
static void ENETPHY_InitState (ENETPHY_Handle hPhyDev);
static void ENETPHY_LinkedState (ENETPHY_Handle hPhyDev);
static void ENETPHY_LinkWaitState (ENETPHY_Handle hPhyDev);
static void ENETPHY_LoopbackState (ENETPHY_Handle hPhyDev);
static void ENETPHY_NwayStartState(ENETPHY_Handle hPhyDev);
static void ENETPHY_NwayWaitState (ENETPHY_Handle hPhyDev);
#define _cpswIsGigPhy(hPhyDev) (TRUE)
#define ENETPHY_NOT_FOUND 0xFFFFu /* Used in Phy Detection */
/*CHECK:: PhyState field breakup */
#define ENETPHY_DEV_OFFSET (0u)
#define ENETPHY_DEV_SIZE (5u)
#define ENETPHY_DEV_MASK (0x1f<<ENETPHY_DEV_OFFSET)
#define ENETPHY_STATE_OFFSET (ENETPHY_DEV_SIZE+ENETPHY_DEV_OFFSET)
#define ENETPHY_STATE_SIZE (5u)
#define ENETPHY_STATE_MASK (0x1fu<<ENETPHY_STATE_OFFSET)
#define INIT (1u<<ENETPHY_STATE_OFFSET)
#define FINDING (2u<<ENETPHY_STATE_OFFSET)
#define FOUND (3u<<ENETPHY_STATE_OFFSET)
#define NWAY_START (4u<<ENETPHY_STATE_OFFSET)
#define NWAY_WAIT (5u<<ENETPHY_STATE_OFFSET)
#define LINK_WAIT (6u<<ENETPHY_STATE_OFFSET)
#define LINKED (7u<<ENETPHY_STATE_OFFSET)
#define LOOPBACK (8u<<ENETPHY_STATE_OFFSET)
#define ENETPHY_SPEED_OFFSET (ENETPHY_STATE_OFFSET+ENETPHY_STATE_SIZE)
#define ENETPHY_SPEED_SIZE (1u)
#define ENETPHY_SPEED_MASK_NDK (1u<<ENETPHY_SPEED_OFFSET)
#define ENETPHY_DUPLEX_OFFSET (ENETPHY_SPEED_OFFSET+ENETPHY_SPEED_SIZE)
#define ENETPHY_DUPLEX_SIZE (1u)
#define ENETPHY_DUPLEX_MASK (1u<<ENETPHY_DUPLEX_OFFSET)
#define ENETPHY_TIM_OFFSET (ENETPHY_DUPLEX_OFFSET+ENETPHY_DUPLEX_SIZE)
#define ENETPHY_TIM_SIZE (10u)
#define ENETPHY_TIM_MASK (0x3ffu<<ENETPHY_TIM_OFFSET)
/* we are working with 100ms ticks here */
#define ENETPHY_FIND_TO ( 1u<<ENETPHY_TIM_OFFSET)
#define ENETPHY_RECK_TO (20u<<ENETPHY_TIM_OFFSET)
#define ENETPHY_LINK_TO (50u<<ENETPHY_TIM_OFFSET)
#define ENETPHY_NWST_TO (50u<<ENETPHY_TIM_OFFSET)
#define ENETPHY_NWDN_TO (80u<<ENETPHY_TIM_OFFSET)
#define ENETPHY_MDIX_TO (27u<<ENETPHY_TIM_OFFSET) /* 2.74 Seconds <--Spec and empirical */
#define ENETPHY_SMODE_OFFSET (ENETPHY_TIM_OFFSET+ENETPHY_TIM_SIZE)
#define ENETPHY_SMODE_SIZE (7u)
#define ENETPHY_SMODE_MASK (0x7fu<<ENETPHY_SMODE_OFFSET)
#define SMODE_LPBK (0x40u<<ENETPHY_SMODE_OFFSET)
#define SMODE_AUTO (0x20u<<ENETPHY_SMODE_OFFSET)
#define SMODE_FD1000 (0x10u<<ENETPHY_SMODE_OFFSET)
#define SMODE_FD100 (0x08u<<ENETPHY_SMODE_OFFSET)
#define SMODE_HD100 (0x04u<<ENETPHY_SMODE_OFFSET)
#define SMODE_FD10 (0x02u<<ENETPHY_SMODE_OFFSET)
#define SMODE_HD10 (0x01u<<ENETPHY_SMODE_OFFSET)
#define SMODE_ALL (0x1fu<<ENETPHY_SMODE_OFFSET)
#define ENETPHY_CHNG_OFFSET (ENETPHY_SMODE_OFFSET+ENETPHY_SMODE_SIZE)
#define ENETPHY_CHNG_SIZE (1u)
#define ENETPHY_CHNG_MASK (1u<<ENETPHY_CHNG_OFFSET)
#define ENETPHY_CHANGE (1u<<ENETPHY_CHNG_OFFSET)
#define ENETPHY_TIMEDOUT_OFFSET (ENETPHY_CHNG_OFFSET+ENETPHY_CHNG_SIZE)
#define ENETPHY_TIMEDOUT_SIZE (1u) /* 30 Bits used */
#define ENETPHY_TIMEDOUT_MASK ((uint32_t)(1u<<ENETPHY_TIMEDOUT_OFFSET))
#define ENETPHY_MDIX_SWITCH ((uint32_t)(1u<<ENETPHY_TIMEDOUT_OFFSET))
#define ENETPHY_MDIX_OFFSET (ENETPHY_TIMEDOUT_OFFSET+ENETPHY_TIMEDOUT_SIZE)
#define ENETPHY_MDIX_SIZE (1u) /* 31 Bits used */
#define ENETPHY_MDIX_MASK ((uint32_t)(1u<<ENETPHY_MDIX_OFFSET))
#define ENETPHY_MDIX ((uint32_t)(1u<<ENETPHY_MDIX_OFFSET))
#ifndef VOLATILE32
#define VOLATILE32(addr) (*((volatile uint32_t *)(addr)))
#endif
int32_t cpsw_g_speed_set = 0;
int32_t cpsw_g_soft_reset_status = 0;
/*User Calls********************************************************* */
/* Updates book-keeping with info provided, programs ControlReg
* with clkdiv,enable bits*/
int32_t ENETPHY_Init(ENETPHY_Handle hPhyDev, uint32_t miibase, uint32_t inst, uint32_t PhyMask, uint32_t MLinkMask, uint32_t MdixMask, uint32_t PhyAddr, uint32_t ResetBit, uint32_t MdioBusFreq, uint32_t MdioClockFreq,int32_t verbose)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
int32_t ret =0 ;
uint32_t phy;
((ENETPHY_DEVICE *) hPhyDev)->miibase = miibase;
((ENETPHY_DEVICE *) hPhyDev)->inst = inst;
((ENETPHY_DEVICE *) hPhyDev)->PhyMask = PhyMask;
((ENETPHY_DEVICE *) hPhyDev)->MLinkMask = MLinkMask;
((ENETPHY_DEVICE *) hPhyDev)->MdixMask = MdixMask;
(void)verbose;/* remove if not required */
*PhyState &= ~ENETPHY_MDIX_MASK; /* Set initial State to MDI */
CSL_MDIO_setClkDivVal((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, (MdioBusFreq/MdioClockFreq - 1));
CSL_MDIO_enableFaultDetect((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase);
CSL_MDIO_disablePreamble((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase);
CSL_MDIO_enableStateMachine((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase);
#ifdef DP83867
#if 0 // debug register access for DP83867
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_PHYIDR1, PhyAddr, &phy);
ENET_PHY_log("DP%d PHYIDR1:0x%X\n", PhyAddr, phy);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_PHYIDR2, PhyAddr, &phy);
ENET_PHY_log("DP%d PHYIDR2:0x%X\n", PhyAddr, phy);
// debug print of bootstrap registers
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_STRAP_STS1, PhyAddr, &phy);
ENET_PHY_log("DP%d STRAP1:0x%X\n", PhyAddr, phy);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_STRAP_STS2, PhyAddr, &phy);
ENET_PHY_log("DP%d STRAP2:0x%X\n", PhyAddr, phy);
#endif
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, PhyAddr, &phy);
phy |= DP_AUTO_NEGOTIATION_ENABLE | DP_DUPLEX_MODE;
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR,PhyAddr,phy);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_ANAR, PhyAddr, &phy);
phy |= DP_TX_FD | DP_TX | DP_10_FD | DP_10BASETE_EN;
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_ANAR,PhyAddr,phy);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_CFG1, PhyAddr, &phy);
phy |= DP_1000BASE_T_FULL_DUPLEX | DP_1000BASE_T_HALF_DUPLEX;
// TM: Disabling 1000M bit mode capability
//phy &= ~((1<<9) | (1<<8));
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_CFG1,PhyAddr,phy);
/* only disable clock out of second PHY */
if(PhyAddr != 0)
{
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_IO_MUX_CFG, PhyAddr, &phy);
phy &= ~(DP_CLK_O_DISABLE);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_IO_MUX_CFG,PhyAddr,phy);
}
/* set RGMII Delay Control Register TX Delay) */
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_RGMIIDCTL, PhyAddr, &phy);
phy &= ~(0xF<<4);
phy |= 0x3<<4; /* set RGMII_TX_DELAY_CTRL to 1.00 ns */
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_RGMIIDCTL, PhyAddr, phy);
#else
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_CNTRL_REG, PhyAddr, &phy);
phy |= NWAY_AUTOMDIX_ENABLE;
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_CNTRL_REG,PhyAddr,phy);
#endif
(void)ResetBit; /* suppress warning */
unsigned int i;
*PhyState=INIT;
ret = 0;
return ret;
}/* end of function ENETPHY_Init*/
void ENETPHY_SetPhyMode(ENETPHY_Handle hPhyDev,uint32_t PhyMode)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t CurrentState;
((ENETPHY_DEVICE *) hPhyDev)->PhyMode = PhyMode; /* used for AUTOMIDX, planned to replace PhyState fields */
*PhyState &= (~ENETPHY_SMODE_MASK);
if (0u != (PhyMode & NWAY_LPBK))
{
*PhyState |= SMODE_LPBK;
}
if (0u != (PhyMode & NWAY_AUTO))
{
*PhyState |= SMODE_AUTO;
}
if (0u != (PhyMode & NWAY_FD1000) )
{
*PhyState |= SMODE_FD1000;
}
if (0u!= (PhyMode & NWAY_FD100))
{
*PhyState |= SMODE_FD100;
}
if (0u != (PhyMode & NWAY_HD100))
{
*PhyState |= SMODE_HD100;
}
if (0u != (PhyMode & NWAY_FD10))
{
*PhyState |= SMODE_FD10;
}
if (0u != (PhyMode & NWAY_HD10))
{
*PhyState |= SMODE_HD10;
}
CurrentState = (*PhyState) & ENETPHY_STATE_MASK;
if ( ((CurrentState == NWAY_START)|| (CurrentState == NWAY_WAIT)) ||
( ((CurrentState == LINK_WAIT) || (CurrentState == LINKED) ) || (CurrentState == LOOPBACK)) )
{
*PhyState = ( (*PhyState)&(~ENETPHY_STATE_MASK)) | (FOUND | ENETPHY_CHANGE);
}
ENET_PHY_log("SetPhyMode:%08x Auto:%d, FD10:%d, HD10:%d, FD100:%d, HD100:%d, FD1000:%d LPBK:%d\n", (unsigned int)PhyMode,
(unsigned int)(PhyMode & NWAY_AUTO), (unsigned int)(PhyMode & MII_NWAY_FD10),(unsigned int)(PhyMode & MII_NWAY_HD10),(unsigned int)(PhyMode & MII_NWAY_FD100),
(unsigned int)(PhyMode & MII_NWAY_HD100), (unsigned int)(PhyMode & NWAY_FD1000),
(unsigned int)(PhyMode & NWAY_LPBK) );
}
uint32_t ENETPHY_GetPhyMode(ENETPHY_Handle hPhyDev)
{
uint32_t PhyMode =0;
uint32_t status_reg = 0,control_reg = 0,advertize_reg;
uint32_t PhyNum,j;
uint32_t PhyMask = ((ENETPHY_DEVICE *) hPhyDev)->PhyMask;
PhyNum = 0;
for(j = 1;PhyNum < 32;PhyNum++)
{
if( 0u != ( j & PhyMask))
{
break;
}
j = j<<1;
}
if(0u != _cpswIsGigPhy(hPhyDev))
{
/* read gig status */
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_1000BT_CONTROL, PhyNum, &control_reg);
/* read gig status */
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_1000BT_STATUS, PhyNum, &status_reg);
}
/* figure out if gig connected at FD 1000 or not first */
if ((0u != (control_reg & MII_NWAY_MY_FD1000)) && (0u != (status_reg & MII_NWAY_REM_FD1000)) )
{
PhyMode |= NWAY_FD1000;
}
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BCR, PhyNum, &control_reg);
if(0u != (control_reg & MII_AUTO_NEGOTIATE_EN) )
{
PhyMode |= NWAY_AUTO;
}
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &status_reg);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_AUTONEG_ADV, PhyNum, &advertize_reg);
/* Check for 10/100 capabilities of PHYs */
if((0u != (control_reg & MII_ENETPHY_100))|| (0u != (PhyMode & NWAY_AUTO)) )
{
if(0u != (advertize_reg & MII_NWAY_FD100))
{
PhyMode |= NWAY_FD100;
}
if(0u != (advertize_reg & MII_NWAY_HD100))
{
PhyMode |= NWAY_HD100;
}
}
if(((control_reg & MII_ENETPHY_100) == 0) || (0u != (PhyMode & NWAY_AUTO)) )
{
if(0u != (advertize_reg & MII_NWAY_FD10))
{
PhyMode |= NWAY_FD10;
}
if(0u != (advertize_reg & MII_NWAY_HD10))
{
PhyMode |= NWAY_HD10;
}
}
return PhyMode;
}
/* ENETPHY_Tic is called every 10 mili seconds to process Phy states */
int32_t ENETPHY_Tic(ENETPHY_Handle hPhyDev,uint32_t* mdioStatus)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t CurrentState;
int32_t ret = 0;
*mdioStatus = MDIO_EVENT_NOCHANGE;
/*Act on current state of the Phy */
CurrentState=*PhyState;
switch(CurrentState&ENETPHY_STATE_MASK)
{
case INIT: ENETPHY_InitState(hPhyDev); break;
case FINDING: ENETPHY_FindingState(hPhyDev); break;
case FOUND: ENETPHY_FoundState(hPhyDev); break;
case NWAY_START: ENETPHY_NwayStartState(hPhyDev); break;
case NWAY_WAIT: ENETPHY_NwayWaitState(hPhyDev); break;
case LINK_WAIT: ENETPHY_LinkWaitState(hPhyDev); break;
case LINKED: ENETPHY_LinkedState(hPhyDev); break;
case LOOPBACK: ENETPHY_LoopbackState(hPhyDev); break;
default: ENETPHY_DefaultState(hPhyDev); break;
}
/* Check is MDI/MDIX mode switch is needed */
if(0u != ((*PhyState) & ENETPHY_MDIX_SWITCH) )
{
uint32_t Mdix;
*PhyState &= (~ENETPHY_MDIX_SWITCH); /* Clear Mdix Flip indicator */
if(0u != ((*PhyState) & ENETPHY_MDIX))
{
Mdix = 1;
}
else
{
Mdix = 0;
}
ret = (int32_t)(_MIIMDIO_MDIXFLIP | Mdix);
}
else
{
/*Return state change to user */
/** CHECK : report MDIO_LINKEVENTS as MDIO_EVENT_NOCHANGE, MDIO_EVENT_LINKDOWN,
* MDIO_EVENT_PHYERROR,MDIO_EVENT_LINKUP
* Currently ENETPHY_CHNG_MASK set for any state transition*/
if (0u != ((*PhyState) & ENETPHY_CHNG_MASK))
{
if( ( ((*PhyState) & ENETPHY_STATE_MASK) == LINKED) && ((CurrentState & ENETPHY_STATE_MASK) != LINKED) )
{
/* we have just entered LInked state */
*mdioStatus = MDIO_EVENT_LINKUP;
}
if( ((CurrentState & ENETPHY_STATE_MASK) == LINKED) && ( ( (*PhyState) & ENETPHY_STATE_MASK) != LINKED))
{
/* we started in Linked state and we have a state change */
*mdioStatus = MDIO_EVENT_LINKDOWN;
}
*PhyState &= (~ENETPHY_CHNG_MASK);
ret = (int32_t)(TRUE);
}
else
{
ret = (int32_t)(FALSE);
}
}
return ret;
}
void ENETPHY_LinkChange(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t PhyNum,PhyStatus;
PhyNum = ( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
ENET_PHY_log("ENETPHY_LinkChange: PhyNum = %d\n", (unsigned int)PhyNum);
if (0u != (ENETPHY_GetLinked(hPhyDev)) )
{
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &PhyStatus);
if ((PhyStatus & MII_ENETPHY_LINKED) == 0u)
{
*PhyState &= (~(ENETPHY_TIM_MASK | ENETPHY_STATE_MASK));
if (0u!=((*PhyState) & SMODE_AUTO))
{
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, MII_AUTO_NEGOTIATE_EN|MII_RENEGOTIATE);
*PhyState |= ((ENETPHY_CHANGE | ENETPHY_NWST_TO) | NWAY_START);
}
else
{
*PhyState|= ((ENETPHY_CHANGE | ENETPHY_LINK_TO) | LINK_WAIT);
}
}
}
}
/* returns 0 if current Phy has AutoMdix support, otherwise 0 */
static int32_t ENETPHY_MdixSupported(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t PhyNum;
int32_t ret;
if((((ENETPHY_DEVICE *) hPhyDev)->PhyMode & NWAY_AUTOMDIX) == 0)
{
ret = (0); /* AutoMdix not turned on */
}
else
{
PhyNum = ((*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
if( ((1<<PhyNum) & ((ENETPHY_DEVICE *) hPhyDev)->MdixMask) == 0)
{
ret = 0; /* Phy does not support AutoMdix*/
}
ret = 1;
}
return ret;
}
/* If current Phy has AutoMdix support add Mdix Delay to the Timer State Value */
static void ENETPHY_MdixDelay(ENETPHY_Handle hPhyDev)
{
uint32_t Delay;
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
if(ENETPHY_MdixSupported(hPhyDev) != 0)
{
/* Get the Delay value in milli-seconds and convert to ten-milli second value */
Delay = cpswRandomRange(_AUTOMDIX_DELAY_MIN, _AUTOMDIX_DELAY_MAX);
Delay /= 10;
/* Add AutoMidx Random Switch Delay to AutoMdix Link Delay */
Delay += (ENETPHY_MDIX_TO>>ENETPHY_TIM_OFFSET);
/* Change Timeout value to AutoMdix standard */
*PhyState &= (~(ENETPHY_TIM_MASK)); /* Clear current Time out value */
*PhyState |= (Delay<<ENETPHY_TIM_OFFSET); /* Set new value */
}
return;
}
void ENETPHY_DisablePhy(ENETPHY_Handle hPhyDev,uint32_t PhyNum)
{
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, (MII_ENETPHY_ISOLATE | MII_ENETPHY_PDOWN) );
ENET_PHY_log("ENETPHY_DisablePhy(%d)\n",(unsigned int)PhyNum);
}
void ENETPHY_InitState(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t CurrentState;
CurrentState=*PhyState;
CurrentState = (CurrentState & (~ENETPHY_TIM_MASK)) | (ENETPHY_FIND_TO);
CurrentState=(CurrentState & (~ENETPHY_STATE_MASK)) | (FINDING);
CurrentState=(CurrentState & (~ENETPHY_SPEED_MASK_NDK));
CurrentState=(CurrentState & (~ENETPHY_DUPLEX_MASK));
CurrentState|=ENETPHY_CHANGE;
*PhyState=CurrentState;
}
void ENETPHY_FindingState(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t PhyMask = ((ENETPHY_DEVICE *) hPhyDev)->PhyMask;
uint32_t PhyNum,i,j;
PhyNum=ENETPHY_NOT_FOUND;
if (0u!= ((*PhyState) & ENETPHY_TIM_MASK))
{
*PhyState=( (*PhyState) & (~ENETPHY_TIM_MASK) ) | (( (*PhyState) & ENETPHY_TIM_MASK) - (1 << ENETPHY_TIM_OFFSET));
}
else
{
j =1;
for(i=0; i<32; i++)
{
if( PhyMask & j)
{
if( CSL_MDIO_isPhyAlive((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, i))
{
PhyNum=i;
break;
}
}
j = j << 1;
}
if (PhyNum!=ENETPHY_NOT_FOUND)
{
/* Phy Found! */
*PhyState = ((*PhyState) & (~ENETPHY_DEV_MASK) ) | ((PhyNum & ENETPHY_DEV_MASK) << ENETPHY_DEV_OFFSET);
*PhyState = ( (*PhyState) & (~ENETPHY_STATE_MASK) ) | (FOUND);
*PhyState|=ENETPHY_CHANGE;
ENET_PHY_log("ENETPHY_FindingState: PhyNum: %d\n",(unsigned int)PhyNum);
}
else
{
ENET_PHY_log("ENETPHY_FindingState: Timed Out looking for a Phy!\n");
*PhyState|=ENETPHY_RECK_TO; /* Set Timer */
}
}
}
void ENETPHY_FoundState(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t PhyMask = ((ENETPHY_DEVICE *) hPhyDev)->PhyMask;
uint32_t MLinkMask = ((ENETPHY_DEVICE *) hPhyDev)->MLinkMask;
uint32_t PhyNum,PhyStatus,NWAYadvertise,NWAY1000advertise=0,m,phynum,i,j;
uint32_t PhyDummy;
static uint32_t auto_neg1 = 0xFFFFFFFF,auto_neg2= 0xFFFFFFFF;
if (( (*PhyState) & ENETPHY_SMODE_MASK) == 0)
{
return;
}
PhyNum = ((*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
j =1;
for(phynum=0; phynum<32; phynum++)
{
if(0u!= (PhyMask & j))
{
if( CSL_MDIO_isPhyAlive((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, phynum))
{
ENETPHY_DisablePhy(hPhyDev,phynum);
}
}
j = j << 1;
}
/* If Aries SWR2 reset then don't reset phy*/
/* Reset the Phy and proceed with auto-negotiation */
if(( 0u != cpsw_g_speed_set) || ((0u ==cpsw_g_soft_reset_status) || ((auto_neg1 & (1 << PhyNum)) == 0) ) )
{
ENETPHY_ResetPhy(hPhyDev,PhyNum);
}
/* Set the way Link will be Monitored */
/* Check the Link Selection Method */
if (0u != ((1 << PhyNum) & MLinkMask) )
{
CSL_MDIO_enableLinkStatusChangeInterrupt((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, ((ENETPHY_DEVICE *) hPhyDev)->inst, PhyNum);
}
else
{
CSL_MDIO_disableLinkStatusChangeInterrupt((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, ((ENETPHY_DEVICE *) hPhyDev)->inst, PhyNum);
}
/* Get the Phy Status */
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &PhyStatus);
/* For Phy Internal loopback test, need to wait until Phy
found, then set Loopback */
if (0u != ((*PhyState) & SMODE_LPBK))
{
/* Set Phy in Loopback */
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, MII_ENETPHY_LOOP|MII_ENETPHY_FD);
/* Do a read to ensure ENETPHY_LOOP has completed */
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &PhyDummy);
*PhyState = ( (*PhyState) & (~ENETPHY_STATE_MASK) ) | (LOOPBACK);
*PhyState|=ENETPHY_CHANGE;
return;
}
ENET_PHY_log("Enable Phy to negotiate external connection\n");
NWAYadvertise=MII_NWAY_SEL;
if (0u != ((*PhyState) & SMODE_FD100))
{
NWAYadvertise |= MII_NWAY_FD100;
}
if (0u != ((*PhyState) & SMODE_HD100))
{
NWAYadvertise |= MII_NWAY_HD100;
}
if (0u != ((*PhyState) & SMODE_FD10))
{
NWAYadvertise |= MII_NWAY_FD10;
}
if (0u != ((*PhyState) & SMODE_HD10))
{
NWAYadvertise |= MII_NWAY_HD10;
}
if (0u != ((*PhyState) & SMODE_FD1000))
{
NWAY1000advertise= ENETPHY_1000BT_FD;
}
*PhyState &= ( ~(ENETPHY_TIM_MASK | ENETPHY_STATE_MASK));
if ((0u != (PhyStatus & MII_NWAY_CAPABLE)) && (0u != ( (*PhyState) & SMODE_AUTO)) ) /*NWAY Phy Detected*/
{
if(( 0u != cpsw_g_speed_set) || ((0u ==cpsw_g_soft_reset_status) || ((auto_neg1 & (1 << PhyNum)) == 0) ) )
{
/*For NWAY compliant Phys */
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_AUTONEG_ADV, PhyNum, NWAYadvertise);
/* for gig negotiation */
if(0u != _cpswIsGigPhy(hPhyDev))
{
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_1000BT_CONTROL, PhyNum, NWAY1000advertise);
}
ENET_PHY_log("NWAY Advertising: ");
if (0u != ((*PhyState) & SMODE_FD1000))
{
ENET_PHY_log("FullDuplex-1000 ");
}
if (0u != (NWAYadvertise & MII_NWAY_FD100))
{
ENET_PHY_log("FullDuplex-100 ");
}
if (0u != (NWAYadvertise & MII_NWAY_HD100))
{
ENET_PHY_log("HalfDuplex-100 ");
}
if (0u != (NWAYadvertise & MII_NWAY_FD10))
{
ENET_PHY_log("FullDuplex-10 ");
}
if (0u != (NWAYadvertise & MII_NWAY_HD10))
{
ENET_PHY_log("HalfDuplex-10 ");
}
ENET_PHY_log("\n");
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, MII_AUTO_NEGOTIATE_EN );
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, MII_AUTO_NEGOTIATE_EN|MII_RENEGOTIATE|MII_ENETPHY_FD);
*PhyState|= ( (ENETPHY_CHANGE | ENETPHY_NWST_TO) | NWAY_START);
}
else
{
*PhyState |= ( (ENETPHY_CHANGE | ENETPHY_NWST_TO) | NWAY_START);
auto_neg1 = auto_neg1 & (~(1 << PhyNum));
}
}
else
{
*PhyState &= (~SMODE_AUTO); /*The Phy is not capable of auto negotiation! */
m=NWAYadvertise;
j = 0x8000u;
for(i=0;(i<16);i++)
{
if(0u != (j & m))
{
break;
}
j = j >> 1 ;
}
m=j;
j=0;
/* figure out if gig connected at FD 1000 or not first */
if ((NWAY1000advertise & MII_NWAY_MY_FD1000)== MII_NWAY_MY_FD1000)
{
j = MII_ENETPHY_1000;
j |= MII_ENETPHY_FD;
}
else
{
if (0u != (m & (MII_NWAY_FD100 | MII_NWAY_HD100)) )
{
j=MII_ENETPHY_100;
m&=(MII_NWAY_FD100|MII_NWAY_HD100);
}
if (0u != (m & (MII_NWAY_FD100 | MII_NWAY_FD10)) )
{
j |= MII_ENETPHY_FD;
}
}
ENET_PHY_log("Requested PHY mode %s Duplex %s Mbps\n",(j & MII_ENETPHY_FD) ? "Full":"Half",
(j & MII_ENETPHY_1000) ? "1000":((j & MII_ENETPHY_100) ? "100":"10"));
if((0u != cpsw_g_speed_set) || ( (0u == cpsw_g_soft_reset_status) || ((auto_neg2 & (1 << PhyNum)) == 0) ))
{
if(0u != (j & MII_ENETPHY_1000))
{
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_1000BT_CONTROL, PhyNum, j);
}
else
{
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, j);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_AUTONEG_ADV, PhyNum, NWAYadvertise);
}
cpsw_g_speed_set = 0;
}
else
{
auto_neg2 = auto_neg2 & (~(1 << PhyNum));
}
*PhyState &= (~ENETPHY_SPEED_MASK_NDK);
if(0u != (j & MII_ENETPHY_1000) )
{
*PhyState|=(1<<ENETPHY_DUPLEX_OFFSET);
((ENETPHY_DEVICE *) hPhyDev)->SPEED_1000 = 1;
}
else
{
((ENETPHY_DEVICE *) hPhyDev)->SPEED_1000 = 0;
}
if (0u != (j & MII_ENETPHY_100) )
{
*PhyState|=(1<<ENETPHY_SPEED_OFFSET);
}
*PhyState &= (~ENETPHY_DUPLEX_MASK);
if (0u != (j & MII_ENETPHY_FD) )
{
*PhyState|=(1<<ENETPHY_DUPLEX_OFFSET);
}
*PhyState |= ((ENETPHY_CHANGE | ENETPHY_LINK_TO) | LINK_WAIT);
}
ENETPHY_MdixDelay(hPhyDev); /* If AutoMdix add delay */
}
void ENETPHY_ResetPhy(ENETPHY_Handle hPhyDev,uint32_t PhyNum)
{
uint32_t data;
data = MII_ENETPHY_RESET;
/* Reset the phy */
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BCR, PhyNum, data);
/* wait till the reset bit is auto cleared */
while(data & MII_ENETPHY_RESET)
{
/* Read the reset */
if(ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BCR, PhyNum, &data) != TRUE)
{
break;
}
}
}
void ENETPHY_SwRestartPhy(ENETPHY_Handle hPhyDev, uint32_t PhyNum)
{
uint32_t data;
data = SW_RESTART;
/* Reset the phy */
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_CTRL, PhyNum, data);
/* wait till the reset bit is auto cleared */
while(data & SW_RESTART)
{
/* Read the reset */
if(ENETPHY_UserAccessRead(hPhyDev, ENETPHY_CTRL, PhyNum, &data) != TRUE)
{
break;
}
}
}
void ENETPHY_NwayStartState(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t PhyNum,PhyMode,PhyDummy;
PhyNum = ( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
/*Wait for Negotiation to start */
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BCR, PhyNum, &PhyMode);
if((PhyMode&MII_RENEGOTIATE)==0)
{
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum,&PhyDummy); /*Flush pending latch bits*/
*PhyState &= (~(ENETPHY_STATE_MASK|ENETPHY_TIM_MASK));
*PhyState |= ((ENETPHY_CHANGE | NWAY_WAIT) |ENETPHY_NWDN_TO);
ENETPHY_MdixDelay(hPhyDev); /* If AutoMdix add delay */
}
else
{
if (0u != ((*PhyState) & ENETPHY_TIM_MASK) )
{
*PhyState=( (*PhyState) & (~ENETPHY_TIM_MASK)) | ( ( (*PhyState) & ENETPHY_TIM_MASK)-(1 << ENETPHY_TIM_OFFSET));
}
else
{
ENETPHY_PhyTimeOut(hPhyDev);
}
}
}
void ENETPHY_NwayWaitState(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t PhyNum,PhyStatus,NWAYadvertise = 0,NWAYREadvertise = 0,NegMode,i,j;
uint32_t NWAY1000advertise = 0, NWAY1000REMadvertise = 0;
PhyNum=( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &PhyStatus);
if (0u != (PhyStatus & MII_NWAY_COMPLETE))
{
*PhyState|=ENETPHY_CHANGE;
*PhyState &= (~ENETPHY_SPEED_MASK_NDK);
*PhyState &= (~ENETPHY_DUPLEX_MASK);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_AUTONEG_ADV, PhyNum, &NWAYadvertise);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_LINK_PARTNER_ABLTY, PhyNum, &NWAYREadvertise);
/* read gig status */
if(0u != _cpswIsGigPhy(hPhyDev))
{
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_1000BT_CONTROL, PhyNum, &NWAY1000advertise);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_1000BT_STATUS, PhyNum, &NWAY1000REMadvertise);
}
/* figure out if gig connected at FD 1000 or not first */
if ((0u !=(NWAY1000advertise & MII_NWAY_MY_FD1000)) && (0u!=(NWAY1000REMadvertise & MII_NWAY_REM_FD1000)) )
{
NegMode = MII_NWAY_MY_FD1000;
}
else
{
NegMode = 0u;
}
if (NegMode == 0u)
{
/* continue checking for 100 and 10 connection */
/* Negotiated mode is we and the remote have in common */
NegMode = NWAYadvertise & NWAYREadvertise;
ENET_PHY_log("Phy: %d, ",(unsigned int)( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET);
ENET_PHY_log("NegMode %04X, NWAYadvertise %04X, NWAYREadvertise %04X\n",
(unsigned int)NegMode, (unsigned int)NWAYadvertise, (unsigned int)NWAYREadvertise);
/* Limit negotiation to fields below */
NegMode &= ( (MII_NWAY_FD100|MII_NWAY_HD100) | (MII_NWAY_FD10|MII_NWAY_HD10));
if (NegMode == 0u)
{
NegMode=(MII_NWAY_HD100|MII_NWAY_HD10)&NWAYadvertise; /*or 10 ?? who knows, Phy is not MII compliant*/
}
j = 0x8000u;
for(i = 0; i <16 ; i++)
{
if (0u != (j & NegMode))
{
break;
}
j = j >> 1;
}
NegMode=j;
ENET_PHY_log("Negotiated connection: ");
if (0u != (NegMode & MII_NWAY_FD100))
{
ENET_PHY_log("FullDuplex 100 Mbs\n");
}
if (0u != (NegMode & MII_NWAY_HD100))
{
ENET_PHY_log("HalfDuplex 100 Mbs\n");
}
if (0u != (NegMode & MII_NWAY_FD10))
{
ENET_PHY_log("FullDuplex 10 Mbs\n");
}
if (0u != (NegMode & MII_NWAY_HD10))
{
ENET_PHY_log("HalfDuplex 10 Mbs\n");
}
((ENETPHY_DEVICE *) hPhyDev)->SPEED_1000 = 0u;
}
else
{
/* found 1000 negotiated connection! */
ENET_PHY_log("Negotiated connection: ");
ENET_PHY_log("FullDuplex 1000 Mbs\n");
((ENETPHY_DEVICE *) hPhyDev)->SPEED_1000 = 1u;
}
if (NegMode != 0u)
{
if (0u != (PhyStatus & MII_ENETPHY_LINKED))
{
*PhyState=( (*PhyState) & (~ENETPHY_STATE_MASK)) | LINKED;
}
else
{
*PhyState=( (*PhyState) & (~ENETPHY_STATE_MASK)) | LINK_WAIT;
}
if (0u != (NegMode & (MII_NWAY_FD100 | MII_NWAY_HD100)) )
{
*PhyState=( (*PhyState) & (~ENETPHY_SPEED_MASK_NDK)) | (1 << ENETPHY_SPEED_OFFSET);
}
if (0u != (NegMode & (MII_NWAY_FD100 | MII_NWAY_FD10 | MII_NWAY_MY_FD1000)))
{
*PhyState=( (*PhyState) & (~ENETPHY_DUPLEX_MASK)) | (1 << ENETPHY_DUPLEX_OFFSET);
}
}
}
else
{
if ( 0u != ( (*PhyState) & ENETPHY_TIM_MASK) )
{
*PhyState=( (*PhyState) & (~ENETPHY_TIM_MASK)) | (( (*PhyState) & ENETPHY_TIM_MASK)-(1 << ENETPHY_TIM_OFFSET));
}
else
{
ENETPHY_PhyTimeOut(hPhyDev);
}
}
}
void ENETPHY_LinkWaitState(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t PhyStatus;
uint32_t PhyNum;
PhyNum=( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BSR, PhyNum, &PhyStatus);
if (0u != (PhyStatus & MII_ENETPHY_LINKED) )
{
*PhyState=( (*PhyState) & (~ENETPHY_STATE_MASK) ) | LINKED;
*PhyState|=ENETPHY_CHANGE;
}
else
{
if (0u != ( (*PhyState) & ENETPHY_TIM_MASK) )
{
*PhyState=(*PhyState&~ENETPHY_TIM_MASK)|((*PhyState&ENETPHY_TIM_MASK)-(1<<ENETPHY_TIM_OFFSET));
}
else
{
ENETPHY_PhyTimeOut(hPhyDev);
}
}
}
void ENETPHY_PhyTimeOut(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState;
if(ENETPHY_MdixSupported(hPhyDev) == 0)
{
return; /* AutoMdix not supported */
}
PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
/* Indicate MDI/MDIX mode switch is needed */
*PhyState|=ENETPHY_MDIX_SWITCH;
/* Toggle the MDIX mode indicatir */
if(0u != ( (*PhyState) & ENETPHY_MDIX) )
{
*PhyState &= (~ENETPHY_MDIX_MASK); /* Current State is MDIX, set to MDI */
}
else
{
*PhyState |= ENETPHY_MDIX_MASK; /* Current State is MDI, set to MDIX */
}
/* Reset state machine to FOUND */
*PhyState = ( (*PhyState) & (~ENETPHY_STATE_MASK)) | (FOUND);
}
void ENETPHY_LoopbackState(ENETPHY_Handle hPhyDev)
{
(void)((ENETPHY_DEVICE *) hPhyDev); /* remove if not needed, to avoid warning */
return;
}
void ENETPHY_LinkedState(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
uint32_t PhyNum = ( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET;
if (CSL_MDIO_isPhyLinked((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, PhyNum))
{
return; /* if still Linked, exit*/
}
/* Not Linked */
*PhyState &= (~(ENETPHY_STATE_MASK | ENETPHY_TIM_MASK));
if (0u != ( (*PhyState) & SMODE_AUTO) )
{
*PhyState |= ( (ENETPHY_CHANGE | NWAY_WAIT) | ENETPHY_NWDN_TO);
}
else
{
*PhyState |= ( (ENETPHY_CHANGE | ENETPHY_LINK_TO) | LINK_WAIT);
}
ENETPHY_MdixDelay(hPhyDev); /* If AutoMdix add delay */
}
void ENETPHY_DefaultState(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
/*Awaiting a ENETPHY_Init call */
*PhyState|=ENETPHY_CHANGE;
}
/* Simple Query Functions for reporting speed,duplex */
/* ENETPHY_GetDuplex is called to retrieve the Duplex info */
int32_t ENETPHY_GetDuplex(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
return(( (*PhyState) & ENETPHY_DUPLEX_MASK) ? 1:0); /* return 0 or a 1 */
}
/* ENETPHY_GetSpeed is called to retreive the Speed info */
int32_t ENETPHY_GetSpeed(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
int32_t ret = 0 ;
if (((ENETPHY_DEVICE *) hPhyDev)->SPEED_1000 == 1)
{
ret = 2; /* if we are linked at 1000, we return a value of 2 */
}
else
{
ret = ( (*PhyState) & ENETPHY_SPEED_MASK_NDK);
}
return ret;
}
/* ENETPHY_GetPhyNum is called to retreive the Phy Device Adr info*/
int32_t ENETPHY_GetPhyNum(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
return((int32_t)(( (*PhyState) & ENETPHY_DEV_MASK) >> ENETPHY_DEV_OFFSET));
}
/* ENETPHY_GetLoopback is called to Determine if the LOOPBACK state has been reached*/
int32_t ENETPHY_GetLoopback(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
return(( (*PhyState) & ENETPHY_STATE_MASK) == LOOPBACK);
}
/* ENETPHY_GetLinked is called to Determine if the LINKED state has been reached*/
int32_t ENETPHY_GetLinked(ENETPHY_Handle hPhyDev)
{
uint32_t *PhyState = &((ENETPHY_DEVICE *) hPhyDev)->PhyState;
return (( (*PhyState) & ENETPHY_STATE_MASK) == LINKED);
}
/************************************
***
*** Waits for MDIO_USERACCESS to be ready and reads data
*** If 'WaitForData' set, waits for read to complete and returns Data,
*** otherwise returns 0
*** Note: 'data' is 16 bits but we use 32 bits
*** to be consistent with rest of the code.
***
**************************************/
uint32_t ENETPHY_UserAccessRead(ENETPHY_Handle hPhyDev, uint32_t regadr, uint32_t phyadr, uint32_t *data)
{
uint16_t data16;
CSL_MDIO_USERACCESS user_access_reg;
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
if(regadr <= 0x1F)
{
//CSL_MDIO_phyRegRead(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, regadr, &data16);
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = regadr;
user_access_reg.write = 0U;
user_access_reg.go = 1U;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* wait for command completion */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
/* Store the data if the read is acknowledged */
if(user_access_reg.ack)
{
*data = user_access_reg.data & MDIO_USERACCESS_DATA;
return 1u;
}
return 0u;
}else
{
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = ENETPHY_REGCR_REG;
user_access_reg.data = EXT_REG_ADDRESS_ACCESS;
user_access_reg.write = 1U;
user_access_reg.go = 1U;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = ENETPHY_ADDR_REG;
user_access_reg.data = regadr;
user_access_reg.write = 1U;
user_access_reg.go = 1U;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = ENETPHY_REGCR_REG;
user_access_reg.data = EXT_REG_DATA_NORMAL_ACCESS;
user_access_reg.write = 1U;
user_access_reg.go = 1U;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = ENETPHY_ADDR_REG;
user_access_reg.write = 0U;
user_access_reg.go = 1U;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
/* Store the data if the read is acknowledged */
if(user_access_reg.ack)
{
*data = user_access_reg.data & MDIO_USERACCESS_DATA;
return 1u;
}
return 0u;
#if 0
CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
EXT_REG_ADDRESS_ACCESS);
CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG,
regadr);
CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
EXT_REG_DATA_NORMAL_ACCESS);
CSL_MDIO_phyRegRead(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG, &data16);
*data = (uint32_t)data16;
#endif
}
return 1;
#if 0
CSL_MDIO_USERACCESS user_access_reg;
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = regadr;
user_access_reg.write = 0U;
user_access_reg.go = 1U;
if(regadr<=0x1F)
{
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
} else // extended register access
{
CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
EXT_REG_ADDRESS_ACCESS);
CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG,
regadr);
CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
EXT_REG_DATA_NORMAL_ACCESS);
CSL_MDIO_phyRegRead(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG, data);
}
/* wait for command completion */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
/* Store the data if the read is acknowledged */
if(user_access_reg.ack)
{
*data = user_access_reg.data & MDIO_USERACCESS_DATA;
return 1u;
}
return 0u;
#endif
}
/************************************
***
*** Waits for MDIO_USERACCESS to be ready and writes data
***
**************************************/
void ENETPHY_UserAccessWrite(ENETPHY_Handle hPhyDev, uint32_t regadr, uint32_t phyadr, uint32_t data)
{
CSL_MDIO_USERACCESS user_access_reg;
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
if(regadr <= 0x1F)
{
//CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, regadr, (uint16_t) data);
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = regadr;
user_access_reg.write = 1U;
user_access_reg.go = 1U;
user_access_reg.data = data;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* wait for command completion */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
}else
{
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = ENETPHY_REGCR_REG;
user_access_reg.data = EXT_REG_ADDRESS_ACCESS;
user_access_reg.write = 1U;
user_access_reg.go = 1U;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = ENETPHY_ADDR_REG;
user_access_reg.data = regadr;
user_access_reg.write = 1U;
user_access_reg.go = 1U;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = ENETPHY_REGCR_REG;
user_access_reg.data = EXT_REG_DATA_NORMAL_ACCESS;
user_access_reg.write = 1U;
user_access_reg.go = 1U;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = ENETPHY_ADDR_REG;
user_access_reg.data = data;
user_access_reg.write = 1U;
user_access_reg.go = 1U;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
#if 0
CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
EXT_REG_ADDRESS_ACCESS);
CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG,
regadr);
CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_REGCR_REG,
EXT_REG_DATA_NORMAL_ACCESS);
CSL_MDIO_phyRegWrite(((ENETPHY_DEVICE *) hPhyDev)->miibase, phyadr, ENETPHY_ADDR_REG, (uint16_t) data);
#endif
}
#if 0
CSL_MDIO_USERACCESS user_access_reg;
/* Wait till transaction completion if any */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
user_access_reg.phyAddr = phyadr;
user_access_reg.regAddr = regadr;
user_access_reg.write = 1U;
user_access_reg.go = 1U;
user_access_reg.data = data;
CSL_MDIO_setUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0U, &user_access_reg);
/* wait for command completion */
do
{
CSL_MDIO_getUserAccessRegister((CSL_mdioHandle) ((ENETPHY_DEVICE *) hPhyDev)->miibase, 0, &user_access_reg);
}
while(user_access_reg.go);
#endif
}
void ENETPHY_SetLoopback(ENETPHY_Handle hPhyDev, uint32_t phyadr, uint32_t loopback_mode)
{
uint32_t data, i;
if(loopback_mode == RGMII_DELAY_CONTROL)
{
ENETPHY_UserAccessRead(hPhyDev, 0x86, phyadr, &data);
for(i=0; i<16; i++)
{
ENETPHY_UserAccessRead(hPhyDev, 0x86, phyadr, &data);
data &= ~(0xf0);
data |= i << 4;
ENETPHY_UserAccessWrite(hPhyDev, 0x86, phyadr, data);
}
return;
}
if(loopback_mode == REVERSE_LOOPBACK)
{
// enable reverse loopback
data = 0x0020;
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BISCR, phyadr, data);
data = 0x4000; // SW restart
ENETPHY_UserAccessWrite(hPhyDev, 0x1f, phyadr, data);
return;
}
if(loopback_mode == DIGITAL_LOOPBACK)
{
// enable reverse loopback
data = 0x8000;
ENETPHY_UserAccessWrite(hPhyDev, 0x1f, phyadr, data);
data = 0x0140;
ENETPHY_UserAccessWrite(hPhyDev, 0x00, phyadr, data);
ENETPHY_UserAccessRead(hPhyDev, 0x32, phyadr, &data);
data = 0x00D3;
ENETPHY_UserAccessWrite(hPhyDev, 0x32, phyadr, data);
data = 0x0004;
ENETPHY_UserAccessWrite(hPhyDev, 0x16, phyadr, data);
data = 0x4000; // SW restart
ENETPHY_UserAccessWrite(hPhyDev, 0x1f, phyadr, data);
return;
}
/* configure the Loopback Configuration Register */
if(loopback_mode == NO_LOOPBACK)
{
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_LOOPCR, phyadr, &data); // debug only
data = 0xE721;
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
}
else
{
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_LOOPCR, phyadr, &data); // debug only
data = 0xE720;
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
}
/* perform a SW_RESTART in LOOPCR register */
ENETPHY_SwRestartPhy(hPhyDev, phyadr);
/* configure the loopback mode */
switch(loopback_mode)
{
case NO_LOOPBACK:
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
data &= ~(0x3Fu);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
data &= ~(1u<<14);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
break;
case MII_LOOPBACK:
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
data &= ~(0x3Fu);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
data |= (1u<<14);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
break;
case PCS_LOOPBACK:
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
data &= ~(0x3Fu);
data |= (1u<<0);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
data &= ~(1u<<14);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
break;
case DIGITAL_LOOPBACK:
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
data &= ~(0x3Fu);
data |= (1u<<2);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
data &= ~(1u<<14);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
break;
case ANALOG_LOOPBACK:
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
data &= ~(0x3Fu);
data |= (2u<<2);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
data &= ~(1u<<14);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
break;
case EXTERNAL_LOOPBACK:
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
data &= ~(0x3Fu);
data |= (4u<<2);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
data &= ~(1u<<14);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
break;
case REVERSE_LOOPBACK:
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BISCR, phyadr, &data);
data &= ~(0x3Fu);
data |= (8u<<2);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_LOOPCR, phyadr, data);
ENETPHY_UserAccessRead(hPhyDev, ENETPHY_BMCR, phyadr, &data);
data &= ~(1u<<14);
ENETPHY_UserAccessWrite(hPhyDev, ENETPHY_BMCR, phyadr, data);
break;
default:
break;
}
}
/********************************************************************************************************************************/
/* void MicroSecDelayWithoutYield(U32 uSDelay) */
/* */
/* Delay for xx microseconds WITHOUT yielding (no TASK switch). This function provides a MINIMUM delay. The actual delay */
/* using this function may be more than you requested (due to HWI/SWI still running). */
/* */
/* Parameters: */
/* - uSDelay: number of microseconds to delay */
/* */
/* Returns: none */
/* */
/* Notes: Public API function that can be called from the TASK level. */
/********************************************************************************************************************************/
void MicroSecDelayWithoutYield(uint32_t uSDelay )
{
UInt task_restore_key = Task_disable(); /* Disable TASKS so we can't get preempted by a higher TASK. */
uint64_t usec_delay_in_ticks = 0;
uint64_t StartTicks = 0;
uint64_t CurrentTicks = 0;
xdc_runtime_Types_FreqHz freq;
xdc_runtime_Types_Timestamp64 BigTicksStamp;
if( uSDelay != 0 )
{
/* Figure out how many ticks it takes to equal 1uS. */
Timestamp_getFreq(&freq);
usec_delay_in_ticks = (uint64_t)((freq.lo / 1000000) * uSDelay);
/* We don't have to worry about checking for a roll over. Our max DSP frequency is 375MHz, or 2.66nS per "tick". A U64
variable is 1.8 x 10 to the 19th power (really f'ing big). It will take over 1500 years for the Timestamp to roll over. */
Timestamp_get64(&BigTicksStamp);
StartTicks = BigTicksStamp.hi;
StartTicks = StartTicks << 32;
StartTicks = StartTicks | BigTicksStamp.lo;
while( CurrentTicks < (StartTicks + usec_delay_in_ticks) )
{
/* Do nothing while we wait for the delay to expire. */
Timestamp_get64(&BigTicksStamp);
CurrentTicks = BigTicksStamp.hi;
CurrentTicks = CurrentTicks << 32;
CurrentTicks = CurrentTicks | BigTicksStamp.lo;
}
}
Task_restore(task_restore_key); /* Restore TASK's to their previous state. */
}