xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/realtek/r8168/rtl_eeprom.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun ################################################################################
4*4882a593Smuzhiyun #
5*4882a593Smuzhiyun # r8168 is the Linux device driver released for Realtek Gigabit Ethernet
6*4882a593Smuzhiyun # controllers with PCI-Express interface.
7*4882a593Smuzhiyun #
8*4882a593Smuzhiyun # Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved.
9*4882a593Smuzhiyun #
10*4882a593Smuzhiyun # This program is free software; you can redistribute it and/or modify it
11*4882a593Smuzhiyun # under the terms of the GNU General Public License as published by the Free
12*4882a593Smuzhiyun # Software Foundation; either version 2 of the License, or (at your option)
13*4882a593Smuzhiyun # any later version.
14*4882a593Smuzhiyun #
15*4882a593Smuzhiyun # This program is distributed in the hope that it will be useful, but WITHOUT
16*4882a593Smuzhiyun # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17*4882a593Smuzhiyun # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18*4882a593Smuzhiyun # more details.
19*4882a593Smuzhiyun #
20*4882a593Smuzhiyun # You should have received a copy of the GNU General Public License along with
21*4882a593Smuzhiyun # this program; if not, see <http://www.gnu.org/licenses/>.
22*4882a593Smuzhiyun #
23*4882a593Smuzhiyun # Author:
24*4882a593Smuzhiyun # Realtek NIC software team <nicfae@realtek.com>
25*4882a593Smuzhiyun # No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
26*4882a593Smuzhiyun #
27*4882a593Smuzhiyun ################################################################################
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /************************************************************************************
31*4882a593Smuzhiyun  *  This product is covered by one or more of the following patents:
32*4882a593Smuzhiyun  *  US6,570,884, US6,115,776, and US6,327,625.
33*4882a593Smuzhiyun  ***********************************************************************************/
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #include <linux/init.h>
36*4882a593Smuzhiyun #include <linux/module.h>
37*4882a593Smuzhiyun #include <linux/version.h>
38*4882a593Smuzhiyun #include <linux/ethtool.h>
39*4882a593Smuzhiyun #include <linux/netdevice.h>
40*4882a593Smuzhiyun #include <linux/delay.h>
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #include <asm/io.h>
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #include "r8168.h"
45*4882a593Smuzhiyun #include "rtl_eeprom.h"
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun //-------------------------------------------------------------------
48*4882a593Smuzhiyun //rtl8168_eeprom_type():
49*4882a593Smuzhiyun //  tell the eeprom type
50*4882a593Smuzhiyun //return value:
51*4882a593Smuzhiyun //  0: the eeprom type is 93C46
52*4882a593Smuzhiyun //  1: the eeprom type is 93C56 or 93C66
53*4882a593Smuzhiyun //-------------------------------------------------------------------
rtl8168_eeprom_type(struct rtl8168_private * tp)54*4882a593Smuzhiyun void rtl8168_eeprom_type(struct rtl8168_private *tp)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun         u16 magic = 0;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun         if (tp->mcfg == CFG_METHOD_DEFAULT)
59*4882a593Smuzhiyun                 goto out_no_eeprom;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun         if(RTL_R8(tp, 0xD2)&0x04) {
62*4882a593Smuzhiyun                 //not support
63*4882a593Smuzhiyun                 //tp->eeprom_type = EEPROM_TWSI;
64*4882a593Smuzhiyun                 //tp->eeprom_len = 256;
65*4882a593Smuzhiyun                 goto out_no_eeprom;
66*4882a593Smuzhiyun         } else if(RTL_R32(tp, RxConfig) & RxCfg_9356SEL) {
67*4882a593Smuzhiyun                 tp->eeprom_type = EEPROM_TYPE_93C56;
68*4882a593Smuzhiyun                 tp->eeprom_len = 256;
69*4882a593Smuzhiyun         } else {
70*4882a593Smuzhiyun                 tp->eeprom_type = EEPROM_TYPE_93C46;
71*4882a593Smuzhiyun                 tp->eeprom_len = 128;
72*4882a593Smuzhiyun         }
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun         magic = rtl8168_eeprom_read_sc(tp, 0);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun out_no_eeprom:
77*4882a593Smuzhiyun         if ((magic != 0x8129) && (magic != 0x8128)) {
78*4882a593Smuzhiyun                 tp->eeprom_type = EEPROM_TYPE_NONE;
79*4882a593Smuzhiyun                 tp->eeprom_len = 0;
80*4882a593Smuzhiyun         }
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
rtl8168_eeprom_cleanup(struct rtl8168_private * tp)83*4882a593Smuzhiyun void rtl8168_eeprom_cleanup(struct rtl8168_private *tp)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun         u8 x;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun         x = RTL_R8(tp, Cfg9346);
88*4882a593Smuzhiyun         x &= ~(Cfg9346_EEDI | Cfg9346_EECS);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, x);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun         rtl8168_raise_clock(tp, &x);
93*4882a593Smuzhiyun         rtl8168_lower_clock(tp, &x);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
rtl8168_eeprom_cmd_done(struct rtl8168_private * tp)96*4882a593Smuzhiyun int rtl8168_eeprom_cmd_done(struct rtl8168_private *tp)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun         u8 x;
99*4882a593Smuzhiyun         int i;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun         rtl8168_stand_by(tp);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun         for (i = 0; i < 50000; i++) {
104*4882a593Smuzhiyun                 x = RTL_R8(tp, Cfg9346);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun                 if (x & Cfg9346_EEDO) {
107*4882a593Smuzhiyun                         udelay(RTL_CLOCK_RATE * 2 * 3);
108*4882a593Smuzhiyun                         return 0;
109*4882a593Smuzhiyun                 }
110*4882a593Smuzhiyun                 udelay(1);
111*4882a593Smuzhiyun         }
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun         return -1;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun //-------------------------------------------------------------------
117*4882a593Smuzhiyun //rtl8168_eeprom_read_sc():
118*4882a593Smuzhiyun //  read one word from eeprom
119*4882a593Smuzhiyun //-------------------------------------------------------------------
rtl8168_eeprom_read_sc(struct rtl8168_private * tp,u16 reg)120*4882a593Smuzhiyun u16 rtl8168_eeprom_read_sc(struct rtl8168_private *tp, u16 reg)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun         int addr_sz = 6;
123*4882a593Smuzhiyun         u8 x;
124*4882a593Smuzhiyun         u16 data;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun         if(tp->eeprom_type == EEPROM_TYPE_NONE) {
127*4882a593Smuzhiyun                 return -1;
128*4882a593Smuzhiyun         }
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun         if (tp->eeprom_type==EEPROM_TYPE_93C46)
131*4882a593Smuzhiyun                 addr_sz = 6;
132*4882a593Smuzhiyun         else if (tp->eeprom_type==EEPROM_TYPE_93C56)
133*4882a593Smuzhiyun                 addr_sz = 8;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun         x = Cfg9346_EEM1 | Cfg9346_EECS;
136*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, x);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, RTL_EEPROM_READ_OPCODE, 3);
139*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, reg, addr_sz);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun         data = rtl8168_shift_in_bits(tp);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun         rtl8168_eeprom_cleanup(tp);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, 0);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun         return data;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun //-------------------------------------------------------------------
151*4882a593Smuzhiyun //rtl8168_eeprom_write_sc():
152*4882a593Smuzhiyun //  write one word to a specific address in the eeprom
153*4882a593Smuzhiyun //-------------------------------------------------------------------
rtl8168_eeprom_write_sc(struct rtl8168_private * tp,u16 reg,u16 data)154*4882a593Smuzhiyun void rtl8168_eeprom_write_sc(struct rtl8168_private *tp, u16 reg, u16 data)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun         u8 x;
157*4882a593Smuzhiyun         int addr_sz = 6;
158*4882a593Smuzhiyun         int w_dummy_addr = 4;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun         if(tp->eeprom_type == EEPROM_TYPE_NONE) {
161*4882a593Smuzhiyun                 return ;
162*4882a593Smuzhiyun         }
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun         if (tp->eeprom_type==EEPROM_TYPE_93C46) {
165*4882a593Smuzhiyun                 addr_sz = 6;
166*4882a593Smuzhiyun                 w_dummy_addr = 4;
167*4882a593Smuzhiyun         } else if (tp->eeprom_type==EEPROM_TYPE_93C56) {
168*4882a593Smuzhiyun                 addr_sz = 8;
169*4882a593Smuzhiyun                 w_dummy_addr = 6;
170*4882a593Smuzhiyun         }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun         x = Cfg9346_EEM1 | Cfg9346_EECS;
173*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, x);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, RTL_EEPROM_EWEN_OPCODE, 5);
176*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, reg, w_dummy_addr);
177*4882a593Smuzhiyun         rtl8168_stand_by(tp);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, RTL_EEPROM_ERASE_OPCODE, 3);
180*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, reg, addr_sz);
181*4882a593Smuzhiyun         if (rtl8168_eeprom_cmd_done(tp) < 0) {
182*4882a593Smuzhiyun                 return;
183*4882a593Smuzhiyun         }
184*4882a593Smuzhiyun         rtl8168_stand_by(tp);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, RTL_EEPROM_WRITE_OPCODE, 3);
187*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, reg, addr_sz);
188*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, data, 16);
189*4882a593Smuzhiyun         if (rtl8168_eeprom_cmd_done(tp) < 0) {
190*4882a593Smuzhiyun                 return;
191*4882a593Smuzhiyun         }
192*4882a593Smuzhiyun         rtl8168_stand_by(tp);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, RTL_EEPROM_EWDS_OPCODE, 5);
195*4882a593Smuzhiyun         rtl8168_shift_out_bits(tp, reg, w_dummy_addr);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun         rtl8168_eeprom_cleanup(tp);
198*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, 0);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
rtl8168_raise_clock(struct rtl8168_private * tp,u8 * x)201*4882a593Smuzhiyun void rtl8168_raise_clock(struct rtl8168_private *tp, u8 *x)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun         *x = *x | Cfg9346_EESK;
204*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, *x);
205*4882a593Smuzhiyun         udelay(RTL_CLOCK_RATE);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
rtl8168_lower_clock(struct rtl8168_private * tp,u8 * x)208*4882a593Smuzhiyun void rtl8168_lower_clock(struct rtl8168_private *tp, u8 *x)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun         *x = *x & ~Cfg9346_EESK;
212*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, *x);
213*4882a593Smuzhiyun         udelay(RTL_CLOCK_RATE);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
rtl8168_shift_out_bits(struct rtl8168_private * tp,int data,int count)216*4882a593Smuzhiyun void rtl8168_shift_out_bits(struct rtl8168_private *tp, int data, int count)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun         u8 x;
219*4882a593Smuzhiyun         int  mask;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun         mask = 0x01 << (count - 1);
222*4882a593Smuzhiyun         x = RTL_R8(tp, Cfg9346);
223*4882a593Smuzhiyun         x &= ~(Cfg9346_EEDI | Cfg9346_EEDO);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun         do {
226*4882a593Smuzhiyun                 if (data & mask)
227*4882a593Smuzhiyun                         x |= Cfg9346_EEDI;
228*4882a593Smuzhiyun                 else
229*4882a593Smuzhiyun                         x &= ~Cfg9346_EEDI;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun                 RTL_W8(tp, Cfg9346, x);
232*4882a593Smuzhiyun                 udelay(RTL_CLOCK_RATE);
233*4882a593Smuzhiyun                 rtl8168_raise_clock(tp, &x);
234*4882a593Smuzhiyun                 rtl8168_lower_clock(tp, &x);
235*4882a593Smuzhiyun                 mask = mask >> 1;
236*4882a593Smuzhiyun         } while(mask);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun         x &= ~Cfg9346_EEDI;
239*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, x);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
rtl8168_shift_in_bits(struct rtl8168_private * tp)242*4882a593Smuzhiyun u16 rtl8168_shift_in_bits(struct rtl8168_private *tp)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun         u8 x;
245*4882a593Smuzhiyun         u16 d, i;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun         x = RTL_R8(tp, Cfg9346);
248*4882a593Smuzhiyun         x &= ~(Cfg9346_EEDI | Cfg9346_EEDO);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun         d = 0;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun         for (i = 0; i < 16; i++) {
253*4882a593Smuzhiyun                 d = d << 1;
254*4882a593Smuzhiyun                 rtl8168_raise_clock(tp, &x);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun                 x = RTL_R8(tp, Cfg9346);
257*4882a593Smuzhiyun                 x &= ~Cfg9346_EEDI;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun                 if (x & Cfg9346_EEDO)
260*4882a593Smuzhiyun                         d |= 1;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun                 rtl8168_lower_clock(tp, &x);
263*4882a593Smuzhiyun         }
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun         return d;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
rtl8168_stand_by(struct rtl8168_private * tp)268*4882a593Smuzhiyun void rtl8168_stand_by(struct rtl8168_private *tp)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun         u8 x;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun         x = RTL_R8(tp, Cfg9346);
273*4882a593Smuzhiyun         x &= ~(Cfg9346_EECS | Cfg9346_EESK);
274*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, x);
275*4882a593Smuzhiyun         udelay(RTL_CLOCK_RATE);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun         x |= Cfg9346_EECS;
278*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, x);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
rtl8168_set_eeprom_sel_low(struct rtl8168_private * tp)281*4882a593Smuzhiyun void rtl8168_set_eeprom_sel_low(struct rtl8168_private *tp)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, Cfg9346_EEM1);
284*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, Cfg9346_EEM1 | Cfg9346_EESK);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun         udelay(20);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun         RTL_W8(tp, Cfg9346, Cfg9346_EEM1);
289*4882a593Smuzhiyun }
290