1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2f485c8a3SMatt Porter /*
3f485c8a3SMatt Porter * ET1011C PHY driver
4f485c8a3SMatt Porter *
5f485c8a3SMatt Porter * Derived from Linux kernel driver by Chaithrika U S
6f485c8a3SMatt Porter * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
7f485c8a3SMatt Porter */
8f485c8a3SMatt Porter #include <config.h>
9f485c8a3SMatt Porter #include <phy.h>
10f485c8a3SMatt Porter
11f485c8a3SMatt Porter #define ET1011C_CONFIG_REG (0x16)
12f485c8a3SMatt Porter #define ET1011C_TX_FIFO_MASK (0x3 << 12)
13f485c8a3SMatt Porter #define ET1011C_TX_FIFO_DEPTH_8 (0x0 << 12)
14f485c8a3SMatt Porter #define ET1011C_TX_FIFO_DEPTH_16 (0x1 << 12)
15f485c8a3SMatt Porter #define ET1011C_INTERFACE_MASK (0x7 << 0)
16f485c8a3SMatt Porter #define ET1011C_GMII_INTERFACE (0x2 << 0)
17f485c8a3SMatt Porter #define ET1011C_SYS_CLK_EN (0x1 << 4)
18f485c8a3SMatt Porter #define ET1011C_TX_CLK_EN (0x1 << 5)
19f485c8a3SMatt Porter
20f485c8a3SMatt Porter #define ET1011C_STATUS_REG (0x1A)
21f485c8a3SMatt Porter #define ET1011C_DUPLEX_STATUS (0x1 << 7)
22f485c8a3SMatt Porter #define ET1011C_SPEED_MASK (0x3 << 8)
23f485c8a3SMatt Porter #define ET1011C_SPEED_1000 (0x2 << 8)
24f485c8a3SMatt Porter #define ET1011C_SPEED_100 (0x1 << 8)
25f485c8a3SMatt Porter #define ET1011C_SPEED_10 (0x0 << 8)
26f485c8a3SMatt Porter
et1011c_config(struct phy_device * phydev)27f485c8a3SMatt Porter static int et1011c_config(struct phy_device *phydev)
28f485c8a3SMatt Porter {
29f485c8a3SMatt Porter int ctl = 0;
30f485c8a3SMatt Porter ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
31f485c8a3SMatt Porter if (ctl < 0)
32f485c8a3SMatt Porter return ctl;
33f485c8a3SMatt Porter ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 |
34f485c8a3SMatt Porter BMCR_ANENABLE);
35f485c8a3SMatt Porter /* First clear the PHY */
36f485c8a3SMatt Porter phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl | BMCR_RESET);
37f485c8a3SMatt Porter
38f485c8a3SMatt Porter return genphy_config_aneg(phydev);
39f485c8a3SMatt Porter }
40f485c8a3SMatt Porter
et1011c_parse_status(struct phy_device * phydev)41f485c8a3SMatt Porter static int et1011c_parse_status(struct phy_device *phydev)
42f485c8a3SMatt Porter {
43f485c8a3SMatt Porter int mii_reg;
44f485c8a3SMatt Porter int speed;
45f485c8a3SMatt Porter
46f485c8a3SMatt Porter mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_STATUS_REG);
47f485c8a3SMatt Porter
48f485c8a3SMatt Porter if (mii_reg & ET1011C_DUPLEX_STATUS)
49f485c8a3SMatt Porter phydev->duplex = DUPLEX_FULL;
50f485c8a3SMatt Porter else
51f485c8a3SMatt Porter phydev->duplex = DUPLEX_HALF;
52f485c8a3SMatt Porter
53f485c8a3SMatt Porter speed = mii_reg & ET1011C_SPEED_MASK;
54f485c8a3SMatt Porter switch (speed) {
55f485c8a3SMatt Porter case ET1011C_SPEED_1000:
56f485c8a3SMatt Porter phydev->speed = SPEED_1000;
57f485c8a3SMatt Porter mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG);
58f485c8a3SMatt Porter mii_reg &= ~ET1011C_TX_FIFO_MASK;
59f485c8a3SMatt Porter phy_write(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG,
60f485c8a3SMatt Porter mii_reg |
61f485c8a3SMatt Porter ET1011C_GMII_INTERFACE |
62f485c8a3SMatt Porter ET1011C_SYS_CLK_EN |
63f485c8a3SMatt Porter #ifdef CONFIG_PHY_ET1011C_TX_CLK_FIX
64f485c8a3SMatt Porter ET1011C_TX_CLK_EN |
65f485c8a3SMatt Porter #endif
66f485c8a3SMatt Porter ET1011C_TX_FIFO_DEPTH_16);
67f485c8a3SMatt Porter break;
68f485c8a3SMatt Porter case ET1011C_SPEED_100:
69f485c8a3SMatt Porter phydev->speed = SPEED_100;
70f485c8a3SMatt Porter break;
71f485c8a3SMatt Porter case ET1011C_SPEED_10:
72f485c8a3SMatt Porter phydev->speed = SPEED_10;
73f485c8a3SMatt Porter break;
74f485c8a3SMatt Porter }
75f485c8a3SMatt Porter
76f485c8a3SMatt Porter return 0;
77f485c8a3SMatt Porter }
78f485c8a3SMatt Porter
et1011c_startup(struct phy_device * phydev)79f485c8a3SMatt Porter static int et1011c_startup(struct phy_device *phydev)
80f485c8a3SMatt Porter {
81b733c278SMichal Simek int ret;
82b733c278SMichal Simek
83b733c278SMichal Simek ret = genphy_update_link(phydev);
84b733c278SMichal Simek if (ret)
85b733c278SMichal Simek return ret;
86b733c278SMichal Simek
87b733c278SMichal Simek return et1011c_parse_status(phydev);
88f485c8a3SMatt Porter }
89f485c8a3SMatt Porter
90f485c8a3SMatt Porter static struct phy_driver et1011c_driver = {
91f485c8a3SMatt Porter .name = "ET1011C",
92f485c8a3SMatt Porter .uid = 0x0282f014,
93f485c8a3SMatt Porter .mask = 0xfffffff0,
94f485c8a3SMatt Porter .features = PHY_GBIT_FEATURES,
95f485c8a3SMatt Porter .config = &et1011c_config,
96f485c8a3SMatt Porter .startup = &et1011c_startup,
97f485c8a3SMatt Porter };
98f485c8a3SMatt Porter
phy_et1011c_init(void)99f485c8a3SMatt Porter int phy_et1011c_init(void)
100f485c8a3SMatt Porter {
101f485c8a3SMatt Porter phy_register(&et1011c_driver);
102f485c8a3SMatt Porter
103f485c8a3SMatt Porter return 0;
104f485c8a3SMatt Porter }
105