import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / net / wan / 8253x / 8253xplx.c
1 /* -*- linux-c -*- */
2
3 /* plx9050.c 
4  * Copyright (C) 2000 by Francois Wautier
5  * based on code from Bjorn Davis
6  * 
7  * Read and write command for the eprom attached to
8  * the PLX9050 
9  */
10
11 /* Modifications and extensions
12  * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version
17  * 2 of the License, or (at your option) any later version.
18  **/
19
20 /* We handle PCI devices */
21 #include <linux/pci.h>      
22
23 /* We need to use ioremap */ 
24 #include <asm/io.h>
25
26 #include <linux/delay.h>
27
28                                 /* Joachim Martillo modified this file */
29                                 /* so that it had no dependencies on specific */
30                                 /* Aurora adapter card or ESSC* structures*/
31                                 /* The original file use TRUE for 1 and */
32                                 /* FALSE for 0.  This convention conflicted */
33                                 /* with other conventions throughout LINUX */
34                                 /* also TRUE was used for setting an eprom */
35                                 /* bit which is a slight semantic confusion. */
36                                 /* I just used 0 and 1 */
37 #include "Reg9050.h"
38
39 /*
40  * Write a single bit to the serial EPROM interface.
41  */
42
43                                 /* eprom_ctl is the */
44                                 /* address of the 9050 */
45                                 /* eprom control register */
46                                 /* The original & operation */
47                                 /* looks wrong.  I am surprised */
48                                 /* the code worked */ 
49                                 /* but I left the parentheses */
50                                 /* because readl, writel etc */
51                                 /* are macros*/
52
53                                 /* The following function */
54                                 /* assumes the proper bit */
55                                 /* in the serial eprom */
56                                 /* has already been selected*/
57
58                                 /* The 9050 registers are 32 bits */
59                                 /* hence the readl and writel */
60                                 /* macros are invoked*/
61
62                                 /* eprom_ctl must be a virtual */
63                                 /* address*/
64
65 static void plx9050_eprom_wbit(unsigned int* eprom_ctl, unsigned int val)
66 {
67         unsigned int     ctrl;
68         
69         /* get the initial value of the CTRL register */
70         ctrl = readl((eprom_ctl));
71         
72         /* set or clear the data bit */
73         if (val) 
74         {
75                 ctrl |= PLX_CTRL_SEPWD;
76         }
77         else 
78         {
79                 ctrl &= ~PLX_CTRL_SEPWD;
80         }
81         
82         writel(ctrl, (eprom_ctl));
83         
84         udelay(1);
85         
86         /* Toggle the clock line */
87         /* gets to the next bit */
88         /* in the serial eprom */
89         ctrl |= PLX_CTRL_SEPCLK;
90         writel(ctrl, (eprom_ctl));
91         
92         udelay(1);
93         
94         /* Toggle the clock line */
95         ctrl &= ~PLX_CTRL_SEPCLK;
96         writel(ctrl, (eprom_ctl));
97         udelay(1);
98 }
99
100 /*
101  * Run a serial EPROM command.  Returns 1 on success,
102  *  0 otherwise.
103  */
104
105 /* This routine does the write of data but only sets up */
106 /* for a read*/
107 /* the write goes from most significant to least significant */
108 unsigned int plx9050_eprom_cmd(unsigned int* eprom_ctl, unsigned char cmd, unsigned char addr, unsigned short data)
109 {
110         unsigned int ctrl;
111         unsigned char shiftb;
112         unsigned short shiftw;
113         unsigned int l, v;
114         unsigned char ret;
115         int i;
116         
117         ret = 1;
118         shiftb = addr << (NM93_BITS_PER_BYTE - NM93_ADDRBITS); /* looks a bizarre way to mask out unused bits */
119         
120         ctrl = readl((eprom_ctl));
121         
122         ctrl &= ~(PLX_CTRL_SEPCLK | PLX_CTRL_SEPWD);
123         writel(ctrl, (eprom_ctl));
124         udelay(1);
125         
126         ctrl |= PLX_CTRL_SEPCS;
127         writel(ctrl, (eprom_ctl));
128         
129         plx9050_eprom_wbit(eprom_ctl, 1);
130         
131         /*
132          * Clock out the command
133          */
134         
135         plx9050_eprom_wbit(eprom_ctl, (cmd & 0x02) != 0);
136         plx9050_eprom_wbit(eprom_ctl, (cmd & 0x01) != 0);
137         
138         /*
139          * Clock out the address
140          */
141         
142         i = NM93_ADDRBITS;
143         while (i != 0)          /* here we get to the correct */
144                                 /* short in the serial eprom*/
145         {
146                 /* printf("Loop #1\n"); */
147                 plx9050_eprom_wbit(eprom_ctl, (shiftb & 0x80) != 0);
148                 
149                 shiftb <<= 1;
150                 i--;
151         }
152         
153         if (cmd == NM93_WRITECMD)       /* now do the write if */
154                 /* a write is to be done*/
155         {       
156                 /* write data? */
157                 /*
158                  * Clock out the data
159                  */
160                 
161                 shiftw = data;
162                 
163                 i = NM93_BITS_PER_WORD;
164                 while (i != 0) {
165                         /* printf("Loop #2\n"); */
166                         plx9050_eprom_wbit(eprom_ctl, (shiftw & 0x8000) != 0);
167                         
168                         shiftw <<= 1;
169                         i--;
170                 }
171                 
172                 /*
173                  * De-assert chip select for a short period of time
174                  */
175                 ctrl = readl((eprom_ctl));
176                 
177                 ctrl &= ~PLX_CTRL_SEPCS;
178                 writel(ctrl, (eprom_ctl));
179                 udelay(2);
180                 
181                 /*
182                  * Re-assert chip select
183                  */
184                 ctrl |= PLX_CTRL_SEPCS;
185                 writel(ctrl, (eprom_ctl));
186                 
187                 /*
188                  * Wait for a low to high transition of DO
189                  */
190                 
191                 i = 20000;
192                 ctrl = readl((eprom_ctl));
193                 l = (ctrl & PLX_CTRL_SEPRD);
194                 
195                 while (i != 0) 
196                 {
197                         /* printf("Loop #3\n"); */
198                         ctrl = readl((eprom_ctl));
199                         v = (ctrl & PLX_CTRL_SEPRD);
200                         if (v != 0 && l == 0) 
201                         {
202                                 break;
203                         }
204                         l = v;
205                         udelay(1);
206                         i--;
207                 }
208                 
209                 if (i == 0) 
210                 {
211                         printk("plx9050: eprom didn't go low to high");
212                         ret = 0;
213                 }
214         }
215         
216         if (cmd != NM93_READCMD)        /* not a read -- terminate */
217         {
218                 /*
219                  * De-assert the chip select.
220                  */
221                 
222                 ctrl = readl((eprom_ctl));
223                 ctrl &= ~PLX_CTRL_SEPCS;
224                 writel(ctrl,(eprom_ctl));
225         }
226         /* otherwise left in read state */
227         return ret;
228 }
229
230 /*
231  * Read the serial EPROM.  Returns 1 on success, 0 on failure.
232  * reads in shorts (i.e., 16 bits at a time.)
233  *
234  */
235
236 unsigned int
237 plx9050_eprom_read(unsigned int* eprom_ctl, unsigned short *ptr, unsigned char addr, unsigned short len)
238 {
239         unsigned short shiftw;
240         int i;
241         unsigned int ctrl;
242         
243         if (!plx9050_eprom_cmd(eprom_ctl, NM93_READCMD, addr, (unsigned short) 0x0)) /* set up read */
244         {
245                 return 0;
246         }
247         
248         ctrl = readl((eprom_ctl));      /* synchronize */
249         
250         while (len-- > 0)               /* now read one word at a time */
251         {
252                 shiftw = 0;
253                 
254                 ctrl &= ~PLX_CTRL_SEPCLK;
255                 writel(ctrl, (eprom_ctl));
256                 
257                 udelay(1);
258                 
259                 i = NM93_BITS_PER_WORD;
260                 while (1)                       /* now read one bit at a time, */
261                         /* left shifting each bit */
262                 {
263                         ctrl |= PLX_CTRL_SEPCLK;
264                         writel(ctrl, (eprom_ctl));
265                         
266                         udelay(1);
267                         
268                         ctrl = readl((eprom_ctl));
269                         
270                         
271                         if ((ctrl & PLX_CTRL_SEPRD) != 0) 
272                         {
273                                 shiftw |= 0x1;
274                         }
275                         
276                         i--;
277                         if (i == 0) 
278                         {
279                                 break;
280                         }
281                         shiftw <<= 1;
282                         
283                         ctrl &= ~PLX_CTRL_SEPCLK;
284                         writel(ctrl, (eprom_ctl));
285                         udelay(1);
286                 }
287                 
288                 *ptr++ = shiftw;
289         }
290         
291         ctrl &= ~PLX_CTRL_SEPCS;
292         writel(ctrl, (eprom_ctl));
293         
294         udelay(1);
295         ctrl &= ~PLX_CTRL_SEPCLK;
296         writel(ctrl, (eprom_ctl));
297         
298         return 1;
299 }