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