summaryrefslogtreecommitdiff
path: root/bsp/nxp/imx/imxrt/libraries/drivers/drv_mdio.c
blob: 0c8076f237c61d25c39897eeec7a173b3c49d465 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

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