2022-05-19 14:06:35 +08:00
|
|
|
|
2020-10-12 18:15:01 +08:00
|
|
|
/*
|
2023-02-11 08:13:40 +08:00
|
|
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
2020-10-12 18:15:01 +08:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*
|
|
|
|
* Change Logs:
|
|
|
|
* Date Author Notes
|
|
|
|
* 2020-09-29 WangQiang the first version
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <rtthread.h>
|
|
|
|
|
|
|
|
#ifdef BSP_USING_PHY
|
|
|
|
|
|
|
|
#define LOG_TAG "drv.mdio"
|
|
|
|
#include <drv_log.h>
|
|
|
|
|
|
|
|
#include <rtdevice.h>
|
|
|
|
#include "drv_mdio.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*! @brief Defines the timeout macro. */
|
|
|
|
#define PHY_TIMEOUT_COUNT 0x3FFFFFFU
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* @brief Get the ENET instance from peripheral base address.
|
|
|
|
*
|
|
|
|
* @param base ENET peripheral base address.
|
|
|
|
* @return ENET instance.
|
|
|
|
*/
|
|
|
|
extern uint32_t ENET_GetInstance(ENET_Type *base);
|
|
|
|
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
|
|
/*! @brief Pointers to enet clocks for each instance. */
|
2022-08-17 16:28:58 +08:00
|
|
|
extern const clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT];
|
2020-10-12 18:15:01 +08:00
|
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
|
|
|
|
|
|
static rt_bool_t rt_hw_mdio_init(void *bus, rt_uint32_t src_clock_hz)
|
|
|
|
{
|
|
|
|
struct rt_mdio_bus *bus_obj = (struct rt_mdio_bus *)bus;
|
|
|
|
uint32_t instance = ENET_GetInstance((ENET_Type *)(bus_obj->hw_obj));
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
|
|
/* Set SMI first. */
|
|
|
|
CLOCK_EnableClock(s_enetClock[instance]);
|
|
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
|
|
ENET_SetSMI((ENET_Type *)(bus_obj->hw_obj), src_clock_hz, RT_FALSE);
|
|
|
|
|
|
|
|
return RT_TRUE;
|
|
|
|
}
|
|
|
|
|
2023-02-06 07:35:33 +08:00
|
|
|
static rt_ssize_t rt_hw_mdio_read(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size)
|
2020-10-12 18:15:01 +08:00
|
|
|
{
|
|
|
|
RT_ASSERT(data);
|
|
|
|
struct rt_mdio_bus *bus_obj = (struct rt_mdio_bus *)bus;
|
|
|
|
|
|
|
|
rt_uint32_t counter;
|
|
|
|
rt_uint32_t *data_ptr = (rt_uint32_t *)data;
|
|
|
|
|
|
|
|
if (4 != size)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear the MII interrupt event. */
|
|
|
|
ENET_ClearInterruptStatus((ENET_Type *)(bus_obj->hw_obj), ENET_EIR_MII_MASK);
|
|
|
|
|
|
|
|
/* Starts a SMI read command operation. */
|
|
|
|
ENET_StartSMIRead((ENET_Type *)(bus_obj->hw_obj), addr, reg, kENET_MiiReadValidFrame);
|
|
|
|
|
|
|
|
/* Wait for MII complete. */
|
|
|
|
for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
|
|
|
|
{
|
|
|
|
if (ENET_GetInterruptStatus((ENET_Type *)(bus_obj->hw_obj)) & ENET_EIR_MII_MASK)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for timeout. */
|
|
|
|
if (!counter)
|
|
|
|
{
|
|
|
|
// return kStatus_PHY_SMIVisitTimeout;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get data from MII register. */
|
|
|
|
*data_ptr = ENET_ReadSMIData((ENET_Type *)(bus_obj->hw_obj));
|
|
|
|
|
|
|
|
/* Clear MII interrupt event. */
|
|
|
|
ENET_ClearInterruptStatus((ENET_Type *)bus_obj->hw_obj, ENET_EIR_MII_MASK);
|
|
|
|
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-02-06 07:35:33 +08:00
|
|
|
static rt_ssize_t rt_hw_mdio_write(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size)
|
2020-10-12 18:15:01 +08:00
|
|
|
{
|
|
|
|
struct rt_mdio_bus *bus_obj = (struct rt_mdio_bus *)bus;
|
|
|
|
uint32_t counter;
|
|
|
|
rt_uint32_t *data_ptr = (rt_uint32_t *)data;
|
|
|
|
|
|
|
|
if (4 != size)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear the SMI interrupt event. */
|
|
|
|
ENET_ClearInterruptStatus((ENET_Type *)(bus_obj->hw_obj), ENET_EIR_MII_MASK);
|
|
|
|
|
|
|
|
/* Starts a SMI write command. */
|
|
|
|
ENET_StartSMIWrite((ENET_Type *)(bus_obj->hw_obj), addr, reg, kENET_MiiWriteValidFrame, *data_ptr);
|
|
|
|
|
|
|
|
/* Wait for SMI complete. */
|
|
|
|
for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
|
|
|
|
{
|
|
|
|
if (ENET_GetInterruptStatus((ENET_Type *)(bus_obj->hw_obj)) & ENET_EIR_MII_MASK)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for timeout. */
|
|
|
|
if (!counter)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear MII interrupt event. */
|
|
|
|
ENET_ClearInterruptStatus((ENET_Type *)(bus_obj->hw_obj), ENET_EIR_MII_MASK);
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct rt_mdio_bus_ops imxrt_mdio_ops =
|
|
|
|
{
|
|
|
|
.init = rt_hw_mdio_init,
|
|
|
|
.read = rt_hw_mdio_read,
|
|
|
|
.write = rt_hw_mdio_write,
|
|
|
|
.uninit = RT_NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static rt_mdio_t mdio_bus;
|
|
|
|
|
|
|
|
rt_mdio_t *rt_hw_mdio_register(void *hw_obj, char *name)
|
|
|
|
{
|
|
|
|
mdio_bus.hw_obj = hw_obj;
|
|
|
|
mdio_bus.name = name;
|
|
|
|
mdio_bus.ops = &imxrt_mdio_ops;
|
|
|
|
return &mdio_bus;
|
|
|
|
}
|
|
|
|
|
|
|
|
rt_mdio_t *rt_hw_mdio_get(void)
|
|
|
|
{
|
|
|
|
return &mdio_bus;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|