Blame view

drivers/net/phy/realtek.c 7.78 KB
097c2aa89   Johnson Leung   phylib: Add Realt...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * drivers/net/phy/realtek.c
   *
   * Driver for Realtek PHYs
   *
   * Author: Johnson Leung <r58129@freescale.com>
   *
   * Copyright (c) 2004 Freescale Semiconductor, Inc.
   *
   * This program is free software; you can redistribute  it and/or modify it
   * under  the terms of  the GNU General  Public License as published by the
   * Free Software Foundation;  either version 2 of the  License, or (at your
   * option) any later version.
   *
   */
8cc5baefb   Martin Blumenstingl   net: phy: realtek...
16
  #include <linux/bitops.h>
097c2aa89   Johnson Leung   phylib: Add Realt...
17
  #include <linux/phy.h>
9d9779e72   Paul Gortmaker   drivers/net: Add ...
18
  #include <linux/module.h>
097c2aa89   Johnson Leung   phylib: Add Realt...
19

f609ab0ed   Martin Blumenstingl   net: phy: realtek...
20
21
22
  #define RTL821x_PHYSR				0x11
  #define RTL821x_PHYSR_DUPLEX			BIT(13)
  #define RTL821x_PHYSR_SPEED			GENMASK(15, 14)
a82f266d2   Martin Blumenstingl   net: phy: realtek...
23

f609ab0ed   Martin Blumenstingl   net: phy: realtek...
24
25
26
27
  #define RTL821x_INER				0x12
  #define RTL8211B_INER_INIT			0x6400
  #define RTL8211E_INER_LINK_STATUS		BIT(10)
  #define RTL8211F_INER_LINK_STATUS		BIT(4)
a82f266d2   Martin Blumenstingl   net: phy: realtek...
28

f609ab0ed   Martin Blumenstingl   net: phy: realtek...
29
  #define RTL821x_INSR				0x13
a82f266d2   Martin Blumenstingl   net: phy: realtek...
30

f609ab0ed   Martin Blumenstingl   net: phy: realtek...
31
  #define RTL821x_PAGE_SELECT			0x1f
097c2aa89   Johnson Leung   phylib: Add Realt...
32

f609ab0ed   Martin Blumenstingl   net: phy: realtek...
33
  #define RTL8211F_INSR				0x1d
ef3d90491   Giuseppe CAVALLARO   net: phy: realtek...
34

f609ab0ed   Martin Blumenstingl   net: phy: realtek...
35
36
37
38
  #define RTL8211F_TX_DELAY			BIT(8)
  
  #define RTL8201F_ISR				0x1e
  #define RTL8201F_IER				0x13
513588dd4   Jassi Brar   net: phy: realtek...
39

d85458256   Linus Walleij   net: phy: realtek...
40
41
  #define RTL8366RB_POWER_SAVE			0x15
  #define RTL8366RB_POWER_SAVE_ON			BIT(12)
097c2aa89   Johnson Leung   phylib: Add Realt...
42
43
44
  MODULE_DESCRIPTION("Realtek PHY driver");
  MODULE_AUTHOR("Johnson Leung");
  MODULE_LICENSE("GPL");
d98c8ccde   Heiner Kallweit   phy: realtek: use...
45
  static int rtl821x_read_page(struct phy_device *phydev)
136819a6e   Martin Blumenstingl   net: phy: realtek...
46
  {
d98c8ccde   Heiner Kallweit   phy: realtek: use...
47
  	return __phy_read(phydev, RTL821x_PAGE_SELECT);
136819a6e   Martin Blumenstingl   net: phy: realtek...
48
  }
d98c8ccde   Heiner Kallweit   phy: realtek: use...
49
  static int rtl821x_write_page(struct phy_device *phydev, int page)
136819a6e   Martin Blumenstingl   net: phy: realtek...
50
  {
d98c8ccde   Heiner Kallweit   phy: realtek: use...
51
  	return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
136819a6e   Martin Blumenstingl   net: phy: realtek...
52
  }
513588dd4   Jassi Brar   net: phy: realtek...
53
54
55
56
57
58
59
60
  static int rtl8201_ack_interrupt(struct phy_device *phydev)
  {
  	int err;
  
  	err = phy_read(phydev, RTL8201F_ISR);
  
  	return (err < 0) ? err : 0;
  }
097c2aa89   Johnson Leung   phylib: Add Realt...
61
62
63
64
65
66
67
68
  static int rtl821x_ack_interrupt(struct phy_device *phydev)
  {
  	int err;
  
  	err = phy_read(phydev, RTL821x_INSR);
  
  	return (err < 0) ? err : 0;
  }
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
69
70
71
  static int rtl8211f_ack_interrupt(struct phy_device *phydev)
  {
  	int err;
d98c8ccde   Heiner Kallweit   phy: realtek: use...
72
  	err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
73
74
75
  
  	return (err < 0) ? err : 0;
  }
513588dd4   Jassi Brar   net: phy: realtek...
76
77
  static int rtl8201_config_intr(struct phy_device *phydev)
  {
136819a6e   Martin Blumenstingl   net: phy: realtek...
78
  	u16 val;
513588dd4   Jassi Brar   net: phy: realtek...
79
80
  
  	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
136819a6e   Martin Blumenstingl   net: phy: realtek...
81
  		val = BIT(13) | BIT(12) | BIT(11);
513588dd4   Jassi Brar   net: phy: realtek...
82
  	else
136819a6e   Martin Blumenstingl   net: phy: realtek...
83
  		val = 0;
513588dd4   Jassi Brar   net: phy: realtek...
84

d98c8ccde   Heiner Kallweit   phy: realtek: use...
85
  	return phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
513588dd4   Jassi Brar   net: phy: realtek...
86
  }
ef3d90491   Giuseppe CAVALLARO   net: phy: realtek...
87
  static int rtl8211b_config_intr(struct phy_device *phydev)
097c2aa89   Johnson Leung   phylib: Add Realt...
88
89
90
91
92
  {
  	int err;
  
  	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  		err = phy_write(phydev, RTL821x_INER,
69021e32e   Martin Blumenstingl   net: phy: realtek...
93
  				RTL8211B_INER_INIT);
097c2aa89   Johnson Leung   phylib: Add Realt...
94
95
96
97
98
  	else
  		err = phy_write(phydev, RTL821x_INER, 0);
  
  	return err;
  }
ef3d90491   Giuseppe CAVALLARO   net: phy: realtek...
99
100
101
102
103
104
  static int rtl8211e_config_intr(struct phy_device *phydev)
  {
  	int err;
  
  	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
  		err = phy_write(phydev, RTL821x_INER,
8b64fd614   Giuseppe CAVALLARO   net: phy: rtl8211...
105
  				RTL8211E_INER_LINK_STATUS);
ef3d90491   Giuseppe CAVALLARO   net: phy: realtek...
106
107
108
109
110
  	else
  		err = phy_write(phydev, RTL821x_INER, 0);
  
  	return err;
  }
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
111
112
  static int rtl8211f_config_intr(struct phy_device *phydev)
  {
136819a6e   Martin Blumenstingl   net: phy: realtek...
113
  	u16 val;
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
114
115
  
  	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
136819a6e   Martin Blumenstingl   net: phy: realtek...
116
  		val = RTL8211F_INER_LINK_STATUS;
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
117
  	else
136819a6e   Martin Blumenstingl   net: phy: realtek...
118
  		val = 0;
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
119

d98c8ccde   Heiner Kallweit   phy: realtek: use...
120
  	return phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
121
  }
d241d4aac   Heiner Kallweit   net: phy: realtek...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  static int rtl8211_config_aneg(struct phy_device *phydev)
  {
  	int ret;
  
  	ret = genphy_config_aneg(phydev);
  	if (ret < 0)
  		return ret;
  
  	/* Quirk was copied from vendor driver. Unfortunately it includes no
  	 * description of the magic numbers.
  	 */
  	if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) {
  		phy_write(phydev, 0x17, 0x2138);
  		phy_write(phydev, 0x0e, 0x0260);
  	} else {
  		phy_write(phydev, 0x17, 0x2108);
  		phy_write(phydev, 0x0e, 0x0000);
  	}
  
  	return 0;
  }
cf87915cb   Heiner Kallweit   net: phy: realtek...
143
144
145
146
147
148
149
150
  static int rtl8211c_config_init(struct phy_device *phydev)
  {
  	/* RTL8211C has an issue when operating in Gigabit slave mode */
  	phy_set_bits(phydev, MII_CTRL1000,
  		     CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
  
  	return genphy_config_init(phydev);
  }
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
151
152
153
  static int rtl8211f_config_init(struct phy_device *phydev)
  {
  	int ret;
d98c8ccde   Heiner Kallweit   phy: realtek: use...
154
  	u16 val = 0;
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
155
156
157
158
  
  	ret = genphy_config_init(phydev);
  	if (ret < 0)
  		return ret;
a24d67573   Eric Lee   Make changes to h...
159
160
161
162
  	/* Set green LED for Link, yellow LED for Active */
  	phy_write(phydev, RTL821x_PAGE_SELECT, 0xd04);
  	phy_write(phydev, 0x10, 0x617f);
  	phy_write(phydev, RTL821x_PAGE_SELECT, 0x0);
e3230494b   Martin Blumenstingl   net: phy: realtek...
163
164
165
  	/* enable TX-delay for rgmii-id and rgmii-txid, otherwise disable it */
  	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
  	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
d98c8ccde   Heiner Kallweit   phy: realtek: use...
166
  		val = RTL8211F_TX_DELAY;
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
167

d98c8ccde   Heiner Kallweit   phy: realtek: use...
168
  	return phy_modify_paged(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY, val);
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
169
  }
049ff57a2   Heiner Kallweit   net: phy: realtek...
170
171
172
173
174
175
176
177
178
179
180
181
182
  static int rtl8211b_suspend(struct phy_device *phydev)
  {
  	phy_write(phydev, MII_MMD_DATA, BIT(9));
  
  	return genphy_suspend(phydev);
  }
  
  static int rtl8211b_resume(struct phy_device *phydev)
  {
  	phy_write(phydev, MII_MMD_DATA, 0);
  
  	return genphy_resume(phydev);
  }
d85458256   Linus Walleij   net: phy: realtek...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  static int rtl8366rb_config_init(struct phy_device *phydev)
  {
  	int ret;
  
  	ret = genphy_config_init(phydev);
  	if (ret < 0)
  		return ret;
  
  	ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE,
  			   RTL8366RB_POWER_SAVE_ON);
  	if (ret) {
  		dev_err(&phydev->mdio.dev,
  			"error enabling power management
  ");
  	}
  
  	return ret;
  }
71b9c4a83   Jongsung Kim   net: phy: realtek...
201
202
203
204
205
206
207
  static struct phy_driver realtek_drvs[] = {
  	{
  		.phy_id         = 0x00008201,
  		.name           = "RTL8201CP Ethernet",
  		.phy_id_mask    = 0x0000ffff,
  		.features       = PHY_BASIC_FEATURES,
  		.flags          = PHY_HAS_INTERRUPT,
71b9c4a83   Jongsung Kim   net: phy: realtek...
208
  	}, {
513588dd4   Jassi Brar   net: phy: realtek...
209
  		.phy_id		= 0x001cc816,
c87de8694   Holger Hoffstätte   net: phy: realtek...
210
  		.name		= "RTL8201F Fast Ethernet",
513588dd4   Jassi Brar   net: phy: realtek...
211
212
213
  		.phy_id_mask	= 0x001fffff,
  		.features	= PHY_BASIC_FEATURES,
  		.flags		= PHY_HAS_INTERRUPT,
513588dd4   Jassi Brar   net: phy: realtek...
214
215
216
217
  		.ack_interrupt	= &rtl8201_ack_interrupt,
  		.config_intr	= &rtl8201_config_intr,
  		.suspend	= genphy_suspend,
  		.resume		= genphy_resume,
d98c8ccde   Heiner Kallweit   phy: realtek: use...
218
219
  		.read_page	= rtl821x_read_page,
  		.write_page	= rtl821x_write_page,
513588dd4   Jassi Brar   net: phy: realtek...
220
  	}, {
d241d4aac   Heiner Kallweit   net: phy: realtek...
221
222
223
224
225
226
227
228
  		.phy_id		= 0x001cc910,
  		.name		= "RTL8211 Gigabit Ethernet",
  		.phy_id_mask	= 0x001fffff,
  		.features	= PHY_GBIT_FEATURES,
  		.config_aneg	= rtl8211_config_aneg,
  		.read_mmd	= &genphy_read_mmd_unsupported,
  		.write_mmd	= &genphy_write_mmd_unsupported,
  	}, {
71b9c4a83   Jongsung Kim   net: phy: realtek...
229
230
231
232
233
  		.phy_id		= 0x001cc912,
  		.name		= "RTL8211B Gigabit Ethernet",
  		.phy_id_mask	= 0x001fffff,
  		.features	= PHY_GBIT_FEATURES,
  		.flags		= PHY_HAS_INTERRUPT,
71b9c4a83   Jongsung Kim   net: phy: realtek...
234
235
  		.ack_interrupt	= &rtl821x_ack_interrupt,
  		.config_intr	= &rtl8211b_config_intr,
0231b1a07   Kevin Hao   net: phy: realtek...
236
237
  		.read_mmd	= &genphy_read_mmd_unsupported,
  		.write_mmd	= &genphy_write_mmd_unsupported,
049ff57a2   Heiner Kallweit   net: phy: realtek...
238
239
  		.suspend	= rtl8211b_suspend,
  		.resume		= rtl8211b_resume,
71b9c4a83   Jongsung Kim   net: phy: realtek...
240
  	}, {
cf87915cb   Heiner Kallweit   net: phy: realtek...
241
242
243
244
245
246
247
248
  		.phy_id		= 0x001cc913,
  		.name		= "RTL8211C Gigabit Ethernet",
  		.phy_id_mask	= 0x001fffff,
  		.features	= PHY_GBIT_FEATURES,
  		.config_init	= rtl8211c_config_init,
  		.read_mmd	= &genphy_read_mmd_unsupported,
  		.write_mmd	= &genphy_write_mmd_unsupported,
  	}, {
0024f8920   Shaohui Xie   net: phy: add Rea...
249
250
251
252
253
  		.phy_id		= 0x001cc914,
  		.name		= "RTL8211DN Gigabit Ethernet",
  		.phy_id_mask	= 0x001fffff,
  		.features	= PHY_GBIT_FEATURES,
  		.flags		= PHY_HAS_INTERRUPT,
0024f8920   Shaohui Xie   net: phy: add Rea...
254
255
256
257
  		.ack_interrupt	= rtl821x_ack_interrupt,
  		.config_intr	= rtl8211e_config_intr,
  		.suspend	= genphy_suspend,
  		.resume		= genphy_resume,
0024f8920   Shaohui Xie   net: phy: add Rea...
258
  	}, {
71b9c4a83   Jongsung Kim   net: phy: realtek...
259
260
261
262
263
  		.phy_id		= 0x001cc915,
  		.name		= "RTL8211E Gigabit Ethernet",
  		.phy_id_mask	= 0x001fffff,
  		.features	= PHY_GBIT_FEATURES,
  		.flags		= PHY_HAS_INTERRUPT,
71b9c4a83   Jongsung Kim   net: phy: realtek...
264
265
266
267
  		.ack_interrupt	= &rtl821x_ack_interrupt,
  		.config_intr	= &rtl8211e_config_intr,
  		.suspend	= genphy_suspend,
  		.resume		= genphy_resume,
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
268
269
270
271
272
273
  	}, {
  		.phy_id		= 0x001cc916,
  		.name		= "RTL8211F Gigabit Ethernet",
  		.phy_id_mask	= 0x001fffff,
  		.features	= PHY_GBIT_FEATURES,
  		.flags		= PHY_HAS_INTERRUPT,
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
274
  		.config_init	= &rtl8211f_config_init,
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
275
276
277
278
  		.ack_interrupt	= &rtl8211f_ack_interrupt,
  		.config_intr	= &rtl8211f_config_intr,
  		.suspend	= genphy_suspend,
  		.resume		= genphy_resume,
d98c8ccde   Heiner Kallweit   phy: realtek: use...
279
280
  		.read_page	= rtl821x_read_page,
  		.write_page	= rtl821x_write_page,
d85458256   Linus Walleij   net: phy: realtek...
281
282
283
284
285
286
287
288
289
  	}, {
  		.phy_id		= 0x001cc961,
  		.name		= "RTL8366RB Gigabit Ethernet",
  		.phy_id_mask	= 0x001fffff,
  		.features	= PHY_GBIT_FEATURES,
  		.flags		= PHY_HAS_INTERRUPT,
  		.config_init	= &rtl8366rb_config_init,
  		.suspend	= genphy_suspend,
  		.resume		= genphy_resume,
71b9c4a83   Jongsung Kim   net: phy: realtek...
290
  	},
097c2aa89   Johnson Leung   phylib: Add Realt...
291
  };
50fd71507   Johan Hovold   net: phy: replace...
292
  module_phy_driver(realtek_drvs);
4e4f10f64   David Woodhouse   phylib: Add modul...
293

cf93c9458   Uwe Kleine-König   net/phy: fix many...
294
  static struct mdio_device_id __maybe_unused realtek_tbl[] = {
513588dd4   Jassi Brar   net: phy: realtek...
295
  	{ 0x001cc816, 0x001fffff },
100ec4bf0   Heiner Kallweit   net: phy: realtek...
296
  	{ 0x001cc910, 0x001fffff },
4e4f10f64   David Woodhouse   phylib: Add modul...
297
  	{ 0x001cc912, 0x001fffff },
04ecac8c1   Heiner Kallweit   net: phy: realtek...
298
  	{ 0x001cc913, 0x001fffff },
0024f8920   Shaohui Xie   net: phy: add Rea...
299
  	{ 0x001cc914, 0x001fffff },
ef3d90491   Giuseppe CAVALLARO   net: phy: realtek...
300
  	{ 0x001cc915, 0x001fffff },
3447cf2e9   Shengzhou Liu   net/phy: Add supp...
301
  	{ 0x001cc916, 0x001fffff },
d85458256   Linus Walleij   net: phy: realtek...
302
  	{ 0x001cc961, 0x001fffff },
4e4f10f64   David Woodhouse   phylib: Add modul...
303
304
305
306
  	{ }
  };
  
  MODULE_DEVICE_TABLE(mdio, realtek_tbl);