/* * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2020-09-29 WangQiang the first version * */ #include #ifdef BSP_USING_PHY #define LOG_TAG "drv.mdio" #include #include #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. */ extern const clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT]; #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; } static rt_ssize_t rt_hw_mdio_read(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size) { 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; } static rt_ssize_t rt_hw_mdio_write(void *bus, rt_uint32_t addr, rt_uint32_t reg, void *data, rt_uint32_t size) { 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