OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 1 | /* This program is free software; you can redistribute it and/or modify |
2 | * it under the terms of the GNU General Public License as published by |
||
3 | * the Free Software Foundation; version 2 of the License |
||
4 | * |
||
5 | * This program is distributed in the hope that it will be useful, |
||
6 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
7 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
8 | * GNU General Public License for more details. |
||
9 | * |
||
10 | * Copyright (C) 2009-2015 John Crispin <blogic@openwrt.org> |
||
11 | * Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name> |
||
12 | * Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com> |
||
13 | */ |
||
14 | |||
15 | #include <linux/module.h> |
||
16 | #include <linux/kernel.h> |
||
17 | #include <linux/types.h> |
||
18 | #include <linux/of_net.h> |
||
19 | #include <linux/of_mdio.h> |
||
20 | |||
21 | #include "mtk_eth_soc.h" |
||
22 | #include "mdio_rt2880.h" |
||
23 | #include "mdio.h" |
||
24 | |||
25 | #define FE_MDIO_RETRY 1000 |
||
26 | |||
27 | static unsigned char *rt2880_speed_str(struct fe_priv *priv) |
||
28 | { |
||
29 | switch (priv->phy->speed[0]) { |
||
30 | case SPEED_1000: |
||
31 | return "1000"; |
||
32 | case SPEED_100: |
||
33 | return "100"; |
||
34 | case SPEED_10: |
||
35 | return "10"; |
||
36 | } |
||
37 | |||
38 | return "?"; |
||
39 | } |
||
40 | |||
41 | void rt2880_mdio_link_adjust(struct fe_priv *priv, int port) |
||
42 | { |
||
43 | u32 mdio_cfg; |
||
44 | |||
45 | if (!priv->link[0]) { |
||
46 | netif_carrier_off(priv->netdev); |
||
47 | netdev_info(priv->netdev, "link down\n"); |
||
48 | return; |
||
49 | } |
||
50 | |||
51 | mdio_cfg = FE_MDIO_CFG_TX_CLK_SKEW_200 | |
||
52 | FE_MDIO_CFG_RX_CLK_SKEW_200 | |
||
53 | FE_MDIO_CFG_GP1_FRC_EN; |
||
54 | |||
55 | if (priv->phy->duplex[0] == DUPLEX_FULL) |
||
56 | mdio_cfg |= FE_MDIO_CFG_GP1_DUPLEX; |
||
57 | |||
58 | if (priv->phy->tx_fc[0]) |
||
59 | mdio_cfg |= FE_MDIO_CFG_GP1_FC_TX; |
||
60 | |||
61 | if (priv->phy->rx_fc[0]) |
||
62 | mdio_cfg |= FE_MDIO_CFG_GP1_FC_RX; |
||
63 | |||
64 | switch (priv->phy->speed[0]) { |
||
65 | case SPEED_10: |
||
66 | mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_10; |
||
67 | break; |
||
68 | case SPEED_100: |
||
69 | mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_100; |
||
70 | break; |
||
71 | case SPEED_1000: |
||
72 | mdio_cfg |= FE_MDIO_CFG_GP1_SPEED_1000; |
||
73 | break; |
||
74 | default: |
||
75 | BUG(); |
||
76 | } |
||
77 | |||
78 | fe_w32(mdio_cfg, FE_MDIO_CFG); |
||
79 | |||
80 | netif_carrier_on(priv->netdev); |
||
81 | netdev_info(priv->netdev, "link up (%sMbps/%s duplex)\n", |
||
82 | rt2880_speed_str(priv), |
||
83 | (priv->phy->duplex[0] == DUPLEX_FULL) ? "Full" : "Half"); |
||
84 | } |
||
85 | |||
86 | static int rt2880_mdio_wait_ready(struct fe_priv *priv) |
||
87 | { |
||
88 | int retries; |
||
89 | |||
90 | retries = FE_MDIO_RETRY; |
||
91 | while (1) { |
||
92 | u32 t; |
||
93 | |||
94 | t = fe_r32(FE_MDIO_ACCESS); |
||
95 | if ((t & BIT(31)) == 0) |
||
96 | return 0; |
||
97 | |||
98 | if (retries-- == 0) |
||
99 | break; |
||
100 | |||
101 | udelay(1); |
||
102 | } |
||
103 | |||
104 | dev_err(priv->dev, "MDIO operation timed out\n"); |
||
105 | return -ETIMEDOUT; |
||
106 | } |
||
107 | |||
108 | int rt2880_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) |
||
109 | { |
||
110 | struct fe_priv *priv = bus->priv; |
||
111 | int err; |
||
112 | u32 t; |
||
113 | |||
114 | err = rt2880_mdio_wait_ready(priv); |
||
115 | if (err) |
||
116 | return 0xffff; |
||
117 | |||
118 | t = (phy_addr << 24) | (phy_reg << 16); |
||
119 | fe_w32(t, FE_MDIO_ACCESS); |
||
120 | t |= BIT(31); |
||
121 | fe_w32(t, FE_MDIO_ACCESS); |
||
122 | |||
123 | err = rt2880_mdio_wait_ready(priv); |
||
124 | if (err) |
||
125 | return 0xffff; |
||
126 | |||
127 | pr_debug("%s: addr=%04x, reg=%04x, value=%04x\n", __func__, |
||
128 | phy_addr, phy_reg, fe_r32(FE_MDIO_ACCESS) & 0xffff); |
||
129 | |||
130 | return fe_r32(FE_MDIO_ACCESS) & 0xffff; |
||
131 | } |
||
132 | |||
133 | int rt2880_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val) |
||
134 | { |
||
135 | struct fe_priv *priv = bus->priv; |
||
136 | int err; |
||
137 | u32 t; |
||
138 | |||
139 | pr_debug("%s: addr=%04x, reg=%04x, value=%04x\n", __func__, |
||
140 | phy_addr, phy_reg, fe_r32(FE_MDIO_ACCESS) & 0xffff); |
||
141 | |||
142 | err = rt2880_mdio_wait_ready(priv); |
||
143 | if (err) |
||
144 | return err; |
||
145 | |||
146 | t = (1 << 30) | (phy_addr << 24) | (phy_reg << 16) | val; |
||
147 | fe_w32(t, FE_MDIO_ACCESS); |
||
148 | t |= BIT(31); |
||
149 | fe_w32(t, FE_MDIO_ACCESS); |
||
150 | |||
151 | return rt2880_mdio_wait_ready(priv); |
||
152 | } |
||
153 | |||
154 | void rt2880_port_init(struct fe_priv *priv, struct device_node *np) |
||
155 | { |
||
156 | const __be32 *id = of_get_property(np, "reg", NULL); |
||
157 | const __be32 *link; |
||
158 | int size; |
||
159 | int phy_mode; |
||
160 | |||
161 | if (!id || (be32_to_cpu(*id) != 0)) { |
||
162 | pr_err("%s: invalid port id\n", np->name); |
||
163 | return; |
||
164 | } |
||
165 | |||
166 | priv->phy->phy_fixed[0] = of_get_property(np, |
||
167 | "mediatek,fixed-link", &size); |
||
168 | if (priv->phy->phy_fixed[0] && |
||
169 | (size != (4 * sizeof(*priv->phy->phy_fixed[0])))) { |
||
170 | pr_err("%s: invalid fixed link property\n", np->name); |
||
171 | priv->phy->phy_fixed[0] = NULL; |
||
172 | return; |
||
173 | } |
||
174 | |||
175 | phy_mode = of_get_phy_mode(np); |
||
176 | switch (phy_mode) { |
||
177 | case PHY_INTERFACE_MODE_RGMII: |
||
178 | break; |
||
179 | case PHY_INTERFACE_MODE_MII: |
||
180 | break; |
||
181 | case PHY_INTERFACE_MODE_RMII: |
||
182 | break; |
||
183 | default: |
||
184 | if (!priv->phy->phy_fixed[0]) |
||
185 | dev_err(priv->dev, "port %d - invalid phy mode\n", |
||
186 | priv->phy->speed[0]); |
||
187 | break; |
||
188 | } |
||
189 | |||
190 | priv->phy->phy_node[0] = of_parse_phandle(np, "phy-handle", 0); |
||
191 | if (!priv->phy->phy_node[0] && !priv->phy->phy_fixed[0]) |
||
192 | return; |
||
193 | |||
194 | if (priv->phy->phy_fixed[0]) { |
||
195 | link = priv->phy->phy_fixed[0]; |
||
196 | priv->phy->speed[0] = be32_to_cpup(link++); |
||
197 | priv->phy->duplex[0] = be32_to_cpup(link++); |
||
198 | priv->phy->tx_fc[0] = be32_to_cpup(link++); |
||
199 | priv->phy->rx_fc[0] = be32_to_cpup(link++); |
||
200 | |||
201 | priv->link[0] = 1; |
||
202 | switch (priv->phy->speed[0]) { |
||
203 | case SPEED_10: |
||
204 | break; |
||
205 | case SPEED_100: |
||
206 | break; |
||
207 | case SPEED_1000: |
||
208 | break; |
||
209 | default: |
||
210 | dev_err(priv->dev, "invalid link speed: %d\n", |
||
211 | priv->phy->speed[0]); |
||
212 | priv->phy->phy_fixed[0] = 0; |
||
213 | return; |
||
214 | } |
||
215 | dev_info(priv->dev, "using fixed link parameters\n"); |
||
216 | rt2880_mdio_link_adjust(priv, 0); |
||
217 | return; |
||
218 | } |
||
219 | |||
220 | if (priv->phy->phy_node[0] && mdiobus_get_phy(priv->mii_bus, 0)) |
||
221 | fe_connect_phy_node(priv, priv->phy->phy_node[0]); |
||
222 | } |