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.

DP83843: DP83843 configuration issue

Part Number: DP83843

Hi,

We are currently using the DP83843 PHY in one automotive project and have issues with proper configurations of it.
I don't need anything specific right now. For now, it will be enough to check if it works properly (simple server with OK/ERR response).

I am sure that the problem is in the configuration because we have a working application where DP83848 is used.

We tried to adapt the existing driver of DP83848 for DP83843 but got no success.

Does TI have some kind of a driver for DP83843? Some guidance/instructions on how to configure it correctly would also be very useful.

Attached driver for DP83848 and our attempt to adapt it for DP83843.

Thank you,
Ruslan.


dp83848.h

2604.dp83848.c
/***********************************************************************************
*
* Copyright © 2017-2019 STMicroelectronics - All Rights Reserved
*
* License terms: STMicroelectronics Proprietary in accordance with licensing
* terms SLA0089 at www.st.com
*
* THIS SOFTWARE IS DISTRIBUTED "AS IS," AND ALL WARRANTIES ARE DISCLAIMED,
* INCLUDING MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* EVALUATION ONLY – NOT FOR USE IN PRODUCTION
************************************************************************************/

/**
 * @file    dp83848.c
 * @brief   Minimal driver to manage the dp83848 10/100 MII/RMII Transceiver
 * @addtogroup PHY
 * @{
 */

#include <stdint.h>
#include <phylib.h>
#include <dp83848.h>
#include <phydrv.h>
#include <projdefs.h>
#include <portmacro.h>
#include <network_cfg.h>
#include <phydev_if.h>

/*******************************************************************************
* Constants and macros
*******************************************************************************/

#define	DP83848_ID      0x20005C90U
#define	DP83848_MASK    0xFFFFFFF0U

/*******************************************************************************
* Global variables
*******************************************************************************/

/*******************************************************************************
* Local types
*******************************************************************************/

/**
 * @brief   Type of a structure representing a DP83848 PHY driver.
 */
typedef struct DP83848Driver DP83848Driver;

/**
 * @brief   Structure representing a DP83848 PHY driver.
 */
struct DP83848Driver {
	void *parent;

	uint32_t addr;
	uint32_t mdix;
	uint32_t interrupts;
	uint32_t mode;
	uint32_t loopback;
};

/*******************************************************************************
* Local function prototypes
*******************************************************************************/

/*******************************************************************************
* Local variables
*******************************************************************************/

#if (SPC5_USE_ETH0 == TRUE)
/**
 * @brief   DP83848 driver instance #1.
 */
static DP83848Driver DP83848D1;
#endif

#if (SPC5_USE_ETH1 == TRUE)
/**
 * @brief   DP83848 driver instance #2.
 */
static DP83848Driver DP83848D2;
#endif

/*******************************************************************************
* Local functions
*******************************************************************************/

/**
 * @brief        Low Level PHY setup
 * @priv	 driver private structure
 * @details      This function aims to setup the transciver according to the parameters
 * 		 passed from the upper layer.
 * 		 The function reset the transceiver and check if the ID registers are
 * 		 reporting the correct mask value.
 * 		 Some internal functionalities can be enabled: e.g. MII or RMII, loopback.
 * 		 The setup fuction, before exiting, restart the auto-negotiation process.
 */
static int dp83848_setup(void *priv)
{
	DP83848Driver *dpd;
	uint16_t val;

	dpd = (DP83848Driver *) priv;

	if (phy_reset(dpd->parent)) {
		return pdFALSE;
	}

	if (phy_check_id(dpd->parent, DP83848_ID, DP83848_MASK)) {
		return pdFALSE;
	}

	/* Auto-MDIX */
	if (dpd->mdix) {
		val = phy_read(dpd->parent, dpd->addr, DP83848_PHYCR);
		val |= DP83848_PHYCR_MDIX_EN;
		phy_write(dpd->parent, dpd->addr, DP83848_PHYCR, val);
	}

	val = phy_read(dpd->parent, dpd->addr, DP83848_RBR);
	if (dpd->mode == SPC5_PHY_MODE_RMII) {
		val |= DP83848_RBR_RMII_MODE;
	} else {
		val &= ~DP83848_RBR_RMII_MODE;
	}
	phy_write(dpd->parent, dpd->addr, DP83848_RBR, val);

	val = 0;
	/* Disable all interrupts */
	if (dpd->interrupts) {
		val = (DP83848_MICR_INT_OE | DP83848_MICR_INT_EN);
	}

	phy_write(dpd->parent, dpd->addr, DP83848_MICR, val);

	if (dpd->loopback) {
		val = phy_read(dpd->parent, dpd->addr, MII_BMCR);
		val &= ~BMCR_ANENABLE;	/* Disable ANE */
		phy_write(dpd->parent, dpd->addr, MII_BMCR, val);

		val = phy_read(dpd->parent, dpd->addr, MII_BMCR);
		val |= BMCR_LOOPBACK;	/* Enable PHY internal loopback */
		phy_write(dpd->parent, dpd->addr, MII_BMCR, val);

		phy_debug(dpd->parent);

		return pdTRUE;
	}

	if (phy_restart_aneg(dpd->parent)) {
		return pdFALSE;
	}

	return pdTRUE;
}

static int dp83848_get_link(void *priv)
{
	DP83848Driver *dpd;
	uint16_t status;
	uint32_t speed, link_mode;

	dpd = (DP83848Driver *) priv;

	status = phy_read(dpd->parent, dpd->addr, DP83848_PHYSTS);

	if ((status & DP83848_PHYSTS_LINK_STATUS) == 0U) {
		phy_set_link(dpd->parent, 0U);
		return pdFALSE;
	}

	/* Link is up */
	phy_set_link(dpd->parent, 1U);

	if ((status & DP83848_PHYSTS_SPEED_STATUS) != 0U) {
		speed = SPC5_PHY_SPEED_10;
	} else {
		speed = SPC5_PHY_SPEED_100;
	}

	if ((status & DP83848_PHYSTS_DUPLEX_STATUS) != 0U) {
		link_mode = SPC5_PHY_LINK_MODE_FULL_DUPLEX;
	} else {
		link_mode = SPC5_PHY_LINK_MODE_HALF_DUPLEX;
	}

	phy_set_speed(dpd->parent, speed);
	phy_set_link_mode(dpd->parent, link_mode);

	return pdTRUE;
}

/*===========================================================================*/
/* Driver interrupt handlers.                                                */
/*===========================================================================*/

/*******************************************************************************
* Global functions
*******************************************************************************/

void dp83848_clean_irq(void *priv)
{
	DP83848Driver *dpd;

	dpd = (DP83848Driver *) priv;

	if (dpd->interrupts) {
		phy_read(dpd->parent, dpd->addr, DP83848_MISR);
	}
}

/**
 * @brief        PHY init
 * @ops		 driver ops callback pointers
 * @details      This function is ivoked by the upper layer to init the PHY driver.
 */
uint32_t dp83848_phydev_init(phydev_ops_t * ops)
{

	DP83848Driver *dpd;
	uint32_t i, val;

	dpd = NULL;

	if (ops->instance == SPC5_ETH0_INSTANCE) {
#if (SPC5_USE_ETH0 == TRUE)
		dpd = &DP83848D1;
		dpd->mode = SPC5_ETH0_PHY_MODE;
#endif
	} else if (ops->instance == SPC5_ETH1_INSTANCE) {
#if (SPC5_USE_ETH1 == TRUE)
		dpd = &DP83848D2;
		dpd->mode = SPC5_ETH1_PHY_MODE;
#endif
	} else {
		return 0xFFFF;
	}

	if (dpd == NULL) {
		return 0xFFFF;
	}

	/* Initialize driver operations */
	ops->setup = dp83848_setup;
	ops->get_link = dp83848_get_link;

	/* Set driver private pointer */
	ops->priv = dpd;

	/* Save reference to parent */
	dpd->parent = ops->parent;
	dpd->mdix = pdFALSE;
	dpd->interrupts = pdFALSE;
	dpd->loopback = pdFALSE;

	for (i = 0; i < PHY_REG_N; i++) {
		val = phy_read(dpd->parent, i, 0x01);
		if (val != 0xffff) {
			dpd->addr = i;
			break;
		}
	}

	if (i == PHY_REG_N) {	/* Reached the end but device not found */
		return 0xFFFF;
	}

	return dpd->addr;
}
/** @} */



dp83843.h
dp83843.c
/***********************************************************************************
*
* Copyright © 2017-2019 STMicroelectronics - All Rights Reserved
*
* License terms: STMicroelectronics Proprietary in accordance with licensing
* terms SLA0089 at www.st.com
*
* THIS SOFTWARE IS DISTRIBUTED "AS IS," AND ALL WARRANTIES ARE DISCLAIMED,
* INCLUDING MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* EVALUATION ONLY – NOT FOR USE IN PRODUCTION
************************************************************************************/

/**
 * @file    dp83848.c
 * @brief   Minimal driver to manage the dp83848 10/100 MII/RMII Transceiver
 * @addtogroup PHY
 * @{
 */

#include <stdint.h>
#include <phylib.h>
#include <dp83848.h>
#include <phydrv.h>
#include <projdefs.h>
#include <portmacro.h>
#include <network_cfg.h>
#include <phydev_if.h>

/*******************************************************************************
* Constants and macros
*******************************************************************************/

#define	DP83843_ID      0x20005C10U
#define	DP83848_MASK    0xFFFFFFF0U

/*******************************************************************************
* Global variables
*******************************************************************************/

/*******************************************************************************
* Local types
*******************************************************************************/

/**
 * @brief   Type of a structure representing a DP83848 PHY driver.
 */
typedef struct DP83848Driver DP83848Driver;

/**
 * @brief   Structure representing a DP83848 PHY driver.
 */
struct DP83848Driver {
	void *parent;

	uint32_t addr;
	uint32_t mdix;
	uint32_t interrupts;
	uint32_t mode;
	uint32_t loopback;
};

/*******************************************************************************
* Local function prototypes
*******************************************************************************/

/*******************************************************************************
* Local variables
*******************************************************************************/

#if (SPC5_USE_ETH0 == TRUE)
/**
 * @brief   DP83848 driver instance #1.
 */
static DP83848Driver DP83848D1;
#endif

#if (SPC5_USE_ETH1 == TRUE)
/**
 * @brief   DP83848 driver instance #2.
 */
static DP83848Driver DP83848D2;
#endif

/*******************************************************************************
* Local functions
*******************************************************************************/

/**
 * @brief        Low Level PHY setup
 * @priv	 driver private structure
 * @details      This function aims to setup the transciver according to the parameters
 * 		 passed from the upper layer.
 * 		 The function reset the transceiver and check if the ID registers are
 * 		 reporting the correct mask value.
 * 		 Some internal functionalities can be enabled: e.g. MII or RMII, loopback.
 * 		 The setup fuction, before exiting, restart the auto-negotiation process.
 */
static int dp83848_setup(void *priv)
{
	DP83848Driver *dpd;
	uint16_t val;

	dpd = (DP83848Driver *) priv;

	if (phy_reset(dpd->parent)) {
		return pdFALSE;
	}

	if (phy_check_id(dpd->parent, DP83843_ID, DP83848_MASK)) {
		return pdFALSE;
	}

	/* not supported on DP83843 */
	/* Auto-MDIX */
	/*
	if (dpd->mdix) {
		val = phy_read(dpd->parent, dpd->addr, DP83848_PHYCR);
		val |= DP83848_PHYCR_MDIX_EN;
		phy_write(dpd->parent, dpd->addr, DP83848_PHYCR, val);
	}

	val = phy_read(dpd->parent, dpd->addr, DP83848_RBR);
	if (dpd->mode == SPC5_PHY_MODE_RMII) {
		val |= DP83848_RBR_RMII_MODE;
	} else {
		val &= ~DP83848_RBR_RMII_MODE;
	}
	phy_write(dpd->parent, dpd->addr, DP83848_RBR, val);
	*/

	val = 0;
	/* Disable all interrupts */
	/*
	if (dpd->interrupts) {
		val = (DP83848_MICR_INT_OE | DP83848_MICR_INT_EN);
	}
	phy_write(dpd->parent, dpd->addr, DP83848_MICR, val);*/

	if (dpd->interrupts) {
		val = (DP83843_MIPSCR_INT_EN);
	}
	phy_write(dpd->parent, dpd->addr, DP83843_MIPSCR, val);


	if (dpd->loopback) {
		val = phy_read(dpd->parent, dpd->addr, MII_BMCR);
		val &= ~BMCR_ANENABLE;	/* Disable ANE */
		phy_write(dpd->parent, dpd->addr, MII_BMCR, val);

		val = phy_read(dpd->parent, dpd->addr, MII_BMCR);
		val |= BMCR_LOOPBACK;	/* Enable PHY internal loopback */
		phy_write(dpd->parent, dpd->addr, MII_BMCR, val);

		phy_debug(dpd->parent);

		return pdTRUE;
	}

//	if (phy_restart_aneg(dpd->parent)) {
//		return pdFALSE;
//	}

	return pdTRUE;
}

static int dp83848_get_link(void *priv)
{
	DP83848Driver *dpd;
	uint16_t status;
	uint32_t speed, link_mode;

	dpd = (DP83848Driver *) priv;

	status = phy_read(dpd->parent, dpd->addr, DP83843_PHYSTS);

	if ((status & DP83843_PHYSTS_LINK_STATUS) == 0U) {
		phy_set_link(dpd->parent, 0U);
		return pdFALSE;
	}

	/* Link is up */
	phy_set_link(dpd->parent, 1U);

	if ((status & DP83843_PHYSTS_SPEED_STATUS) != 0U) {
		speed = SPC5_PHY_SPEED_10;
	} else {
		speed = SPC5_PHY_SPEED_100;
	}

	if ((status & DP83843_PHYSTS_DUPLEX_STATUS) != 0U) {
		link_mode = SPC5_PHY_LINK_MODE_FULL_DUPLEX;
	} else {
		link_mode = SPC5_PHY_LINK_MODE_HALF_DUPLEX;
	}

	phy_set_speed(dpd->parent, speed);
	phy_set_link_mode(dpd->parent, link_mode);

	return pdTRUE;
}

/*===========================================================================*/
/* Driver interrupt handlers.                                                */
/*===========================================================================*/

/*******************************************************************************
* Global functions
*******************************************************************************/

void dp83848_clean_irq(void *priv)
{
	DP83848Driver *dpd;

	dpd = (DP83848Driver *) priv;

	if (dpd->interrupts) {
		phy_read(dpd->parent, dpd->addr, DP83843_MIPGSR);
	}
}

/**
 * @brief        PHY init
 * @ops		 driver ops callback pointers
 * @details      This function is ivoked by the upper layer to init the PHY driver.
 */
uint32_t dp83848_phydev_init(phydev_ops_t * ops)
{

	DP83848Driver *dpd;
	uint32_t i, val;

	dpd = NULL;

	if (ops->instance == SPC5_ETH0_INSTANCE) {
#if (SPC5_USE_ETH0 == TRUE)
		dpd = &DP83848D1;
		dpd->mode = SPC5_ETH0_PHY_MODE;
#endif
	} else if (ops->instance == SPC5_ETH1_INSTANCE) {
#if (SPC5_USE_ETH1 == TRUE)
		dpd = &DP83848D2;
		dpd->mode = SPC5_ETH1_PHY_MODE;
#endif
	} else {
		return 0xFFFF;
	}

	if (dpd == NULL) {
		return 0xFFFF;
	}

	/* Initialize driver operations */
	ops->setup = dp83848_setup;
	ops->get_link = dp83848_get_link;

	/* Set driver private pointer */
	ops->priv = dpd;

	/* Save reference to parent */
	dpd->parent = ops->parent;
	dpd->mdix = pdFALSE;
	dpd->interrupts = pdFALSE;
	dpd->loopback = pdFALSE;

	for (i = 0; i < PHY_REG_N; i++) {
		val = phy_read(dpd->parent, i, 0x01);
		if (val != 0xffff) {
			dpd->addr = i;
			break;
		}
	}

	if (i == PHY_REG_N) {	/* Reached the end but device not found */
		return 0xFFFF;
	}

	return dpd->addr;
}
/** @} */