]>
Commit | Line | Data |
---|---|---|
f41e588c SDPP |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Xilinx GMII2RGMII phy driver | |
4 | * | |
5 | * Copyright (C) 2018 Xilinx, Inc. | |
6 | */ | |
7 | ||
401d1c4f | 8 | #include <common.h> |
f41e588c | 9 | #include <dm.h> |
f7ae49fc | 10 | #include <log.h> |
f41e588c | 11 | #include <phy.h> |
401d1c4f | 12 | #include <asm/global_data.h> |
f41e588c SDPP |
13 | |
14 | DECLARE_GLOBAL_DATA_PTR; | |
15 | ||
16 | #define ZYNQ_GMII2RGMII_REG 0x10 | |
17 | #define ZYNQ_GMII2RGMII_SPEED_MASK (BMCR_SPEED1000 | BMCR_SPEED100) | |
18 | ||
19 | static int xilinxgmiitorgmii_config(struct phy_device *phydev) | |
20 | { | |
21 | struct phy_device *ext_phydev = phydev->priv; | |
22 | ||
23 | debug("%s\n", __func__); | |
24 | if (ext_phydev->drv->config) | |
25 | ext_phydev->drv->config(ext_phydev); | |
26 | ||
27 | return 0; | |
28 | } | |
29 | ||
30 | static int xilinxgmiitorgmii_extread(struct phy_device *phydev, int addr, | |
31 | int devaddr, int regnum) | |
32 | { | |
33 | struct phy_device *ext_phydev = phydev->priv; | |
34 | ||
35 | debug("%s\n", __func__); | |
36 | if (ext_phydev->drv->readext) | |
37 | ext_phydev->drv->readext(ext_phydev, addr, devaddr, regnum); | |
38 | ||
39 | return 0; | |
40 | } | |
41 | ||
42 | static int xilinxgmiitorgmii_extwrite(struct phy_device *phydev, int addr, | |
43 | int devaddr, int regnum, u16 val) | |
44 | ||
45 | { | |
46 | struct phy_device *ext_phydev = phydev->priv; | |
47 | ||
48 | debug("%s\n", __func__); | |
49 | if (ext_phydev->drv->writeext) | |
50 | ext_phydev->drv->writeext(ext_phydev, addr, devaddr, regnum, | |
51 | val); | |
52 | ||
53 | return 0; | |
54 | } | |
55 | ||
56 | static int xilinxgmiitorgmii_startup(struct phy_device *phydev) | |
57 | { | |
58 | u16 val = 0; | |
59 | struct phy_device *ext_phydev = phydev->priv; | |
60 | ||
61 | debug("%s\n", __func__); | |
62 | ext_phydev->dev = phydev->dev; | |
63 | if (ext_phydev->drv->startup) | |
64 | ext_phydev->drv->startup(ext_phydev); | |
65 | ||
66 | val = phy_read(phydev, phydev->addr, ZYNQ_GMII2RGMII_REG); | |
67 | val &= ~ZYNQ_GMII2RGMII_SPEED_MASK; | |
68 | ||
69 | if (ext_phydev->speed == SPEED_1000) | |
70 | val |= BMCR_SPEED1000; | |
71 | else if (ext_phydev->speed == SPEED_100) | |
72 | val |= BMCR_SPEED100; | |
73 | ||
74 | phy_write(phydev, phydev->addr, ZYNQ_GMII2RGMII_REG, val | | |
75 | BMCR_FULLDPLX); | |
76 | ||
77 | phydev->duplex = ext_phydev->duplex; | |
78 | phydev->speed = ext_phydev->speed; | |
79 | phydev->link = ext_phydev->link; | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
84 | static int xilinxgmiitorgmii_probe(struct phy_device *phydev) | |
85 | { | |
86 | int ofnode = phydev->addr; | |
87 | u32 phy_of_handle; | |
88 | int ext_phyaddr = -1; | |
89 | struct phy_device *ext_phydev; | |
90 | ||
91 | debug("%s\n", __func__); | |
92 | ||
93 | if (phydev->interface != PHY_INTERFACE_MODE_GMII) { | |
94 | printf("Incorrect interface type\n"); | |
95 | return -EINVAL; | |
96 | } | |
97 | ||
98 | /* | |
99 | * Read the phy address again as the one we read in ethernet driver | |
100 | * was overwritten for the purpose of storing the ofnode | |
101 | */ | |
102 | phydev->addr = fdtdec_get_int(gd->fdt_blob, ofnode, "reg", -1); | |
103 | phy_of_handle = fdtdec_lookup_phandle(gd->fdt_blob, ofnode, | |
104 | "phy-handle"); | |
105 | if (phy_of_handle > 0) | |
106 | ext_phyaddr = fdtdec_get_int(gd->fdt_blob, | |
107 | phy_of_handle, | |
108 | "reg", -1); | |
109 | ext_phydev = phy_find_by_mask(phydev->bus, | |
110 | 1 << ext_phyaddr, | |
111 | PHY_INTERFACE_MODE_RGMII); | |
112 | if (!ext_phydev) { | |
113 | printf("%s, No external phy device found\n", __func__); | |
114 | return -EINVAL; | |
115 | } | |
116 | ||
117 | ext_phydev->node = offset_to_ofnode(phy_of_handle); | |
118 | phydev->priv = ext_phydev; | |
119 | ||
120 | debug("%s, gmii2rgmmi:0x%x, extphy:0x%x\n", __func__, phydev->addr, | |
121 | ext_phyaddr); | |
122 | ||
123 | phydev->flags |= PHY_FLAG_BROKEN_RESET; | |
124 | ||
125 | return 0; | |
126 | } | |
127 | ||
128 | static struct phy_driver gmii2rgmii_driver = { | |
129 | .name = "XILINX GMII2RGMII", | |
130 | .uid = PHY_GMII2RGMII_ID, | |
131 | .mask = 0xffffffff, | |
132 | .features = PHY_GBIT_FEATURES, | |
133 | .probe = xilinxgmiitorgmii_probe, | |
134 | .config = xilinxgmiitorgmii_config, | |
135 | .startup = xilinxgmiitorgmii_startup, | |
136 | .writeext = xilinxgmiitorgmii_extwrite, | |
137 | .readext = xilinxgmiitorgmii_extread, | |
138 | }; | |
139 | ||
140 | int phy_xilinx_gmii2rgmii_init(void) | |
141 | { | |
142 | phy_register(&gmii2rgmii_driver); | |
143 | ||
144 | return 0; | |
145 | } |