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. */ }