ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / net / fc / iph5526_novram.c
1 /********************************************************************** 
2  * Reading the NVRAM on the Interphase 5526 PCI Fibre Channel Card. 
3  * All contents in this file : courtesy Interphase Corporation.
4  * Special thanks to Kevin Quick, kquick@iphase.com.
5  **********************************************************************/
6
7 #define FF_MAGIC        0x4646
8 #define DB_MAGIC        0x4442
9 #define DL_MAGIC        0x444d
10
11
12 #define CMD_LEN         9
13
14 /***********
15  *
16  *      Switches and defines for header files.
17  *
18  *      The following defines are used to turn on and off
19  *      various options in the header files. Primarily useful
20  *      for debugging.
21  *
22  ***********/
23
24 static const unsigned short novram_default[4] = {
25     FF_MAGIC,
26     DB_MAGIC,
27     DL_MAGIC,
28     0 };
29
30
31 /*
32  * a list of the commands that can be sent to the NOVRAM
33  */
34
35 #define NR_EXTEND  0x100
36 #define NR_WRITE   0x140
37 #define NR_READ    0x180
38 #define NR_ERASE   0x1c0
39
40 #define EWDS    0x00
41 #define WRAL    0x10
42 #define ERAL    0x20
43 #define EWEN    0x30
44
45 /*
46  * Defines for the pins on the NOVRAM
47  */
48
49 #define BIT(x)          (1 << (x))
50
51 #define NVDI_B          31
52 #define NVDI            BIT(NVDI_B)
53 #define NVDO            BIT(9)
54 #define NVCE            BIT(30)
55 #define NVSK            BIT(29)
56 #define NV_MANUAL       BIT(28)
57
58 /***********
59  *
60  *      Include files.
61  *
62  ***********/
63
64 #define KeStallExecutionProcessor(x)    {volatile int d, p;\
65                   for (d=0; d<x; d++) for (p=0; p<10; p++);\
66                                      }
67
68
69 /***********************
70  *
71  * This define ands the value and the current config register and puts
72  * the result in the config register
73  *
74  ***********************/
75
76 #define CFG_AND(val) { volatile int t; \
77                            t = readl(fi->n_r.ptr_novram_hw_control_reg);   \
78                            t &= (val);                                  \
79                            writel(t, fi->n_r.ptr_novram_hw_control_reg);   \
80                    }
81
82 /***********************
83  *
84  * This define ors the value and the current config register and puts
85  * the result in the config register
86  *
87  ***********************/
88
89 #define CFG_OR(val) { volatile int t; \
90                            t = readl(fi->n_r.ptr_novram_hw_control_reg);   \
91                            t |= (val);                                  \
92                            writel(t, fi->n_r.ptr_novram_hw_control_reg);   \
93                    }
94
95 /***********************
96  *
97  * Send a command to the NOVRAM, the command is in cmd.
98  *
99  * clear CE and SK. Then assert CE.
100  * Clock each of the command bits out in the correct order with SK
101  * exit with CE still asserted
102  *
103  ***********************/
104
105 #define NVRAM_CMD(cmd) { int i; \
106                          int c = cmd; \
107                          CFG_AND(~(NVCE|NVSK)); \
108                          CFG_OR(NVCE); \
109                          for (i=0; i<CMD_LEN; i++) { \
110                              NVRAM_CLKOUT((c & (1 << (CMD_LEN - 1))) ? 1 : 0);\
111                              c <<= 1; } }
112
113 /***********************
114  *
115  * clear the CE, this must be used after each command is complete
116  *
117  ***********************/
118
119 #define NVRAM_CLR_CE    CFG_AND(~NVCE)
120
121 /***********************
122  *
123  * clock the data bit in bitval out to the NOVRAM.  The bitval must be
124  * a 1 or 0, or the clockout operation is undefined
125  *
126  ***********************/
127
128 #define NVRAM_CLKOUT(bitval) {\
129                            CFG_AND(~NVDI); \
130                            CFG_OR((bitval) << NVDI_B); \
131                            KeStallExecutionProcessor(5);\
132                            CFG_OR(NVSK); \
133                            KeStallExecutionProcessor(5);\
134                            CFG_AND( ~NVSK); \
135                            }
136
137 /***********************
138  *
139  * clock the data bit in and return a 1 or 0, depending on the value
140  * that was received from the NOVRAM
141  *
142  ***********************/
143
144 #define NVRAM_CLKIN(val)        {\
145                        CFG_OR(NVSK); \
146                            KeStallExecutionProcessor(5);\
147                        CFG_AND(~NVSK); \
148                            KeStallExecutionProcessor(5);\
149                        val = (readl(fi->n_r.ptr_novram_hw_status_reg) & NVDO) ? 1 : 0; \
150                        }
151
152 /***********
153  *
154  *      Function Prototypes
155  *
156  ***********/
157
158 static int iph5526_nr_get(struct fc_info *fi, int addr);
159 static void iph5526_nr_do_init(struct fc_info *fi);
160 static void iph5526_nr_checksum(struct fc_info *fi);
161
162
163 /*******************************************************************
164  *
165  *      Local routine:  iph5526_nr_do_init
166  *      Purpose:        initialize novram server
167  *      Description:
168  *
169  *      iph5526_nr_do_init reads the novram into the temporary holding place.
170  *      A checksum is done on the area and the Magic Cookies are checked.
171  *      If any of them are bad, the NOVRAM is initialized with the 
172  *      default values and a warning message is displayed.
173  *
174  *******************************************************************/
175
176 static void iph5526_nr_do_init(struct fc_info *fi)
177 {
178     int i;
179     unsigned short chksum = 0;
180     int bad = 0;
181
182     for (i=0; i<IPH5526_NOVRAM_SIZE; i++) {
183         fi->n_r.data[i] = iph5526_nr_get(fi, i);
184         chksum += fi->n_r.data[i];
185     }
186
187     if (chksum) 
188         bad = 1;
189
190     if (fi->n_r.data[IPH5526_NOVRAM_SIZE - 4] != FF_MAGIC)
191         bad = 1;
192     if (fi->n_r.data[IPH5526_NOVRAM_SIZE - 3] != DB_MAGIC)
193         bad = 1;                 
194         if (fi->n_r.data[IPH5526_NOVRAM_SIZE - 2] != DL_MAGIC)
195         bad = 1;
196
197     if (bad) {
198         for (i=0; i<IPH5526_NOVRAM_SIZE; i++) {
199             if (i < (IPH5526_NOVRAM_SIZE - 4)) {
200                 fi->n_r.data[i] = 0xffff;
201             } else {
202                 fi->n_r.data[i] = novram_default[i - (IPH5526_NOVRAM_SIZE - 4)];
203             }
204         }
205         iph5526_nr_checksum(fi);
206     }
207 }
208
209
210 /*******************************************************************
211  *
212  *      Local routine:  iph5526_nr_get
213  *      Purpose:        read a single word of NOVRAM
214  *      Description:
215  *
216  *      read the 16 bits that make up a word addr of the novram.  
217  *      The 16 bits of data that are read are returned as the return value
218  *
219  *******************************************************************/
220
221 static int iph5526_nr_get(struct fc_info *fi, int addr)
222 {
223     int i;
224     int t;
225     int val = 0;
226
227     CFG_OR(NV_MANUAL);
228
229     /*
230      * read the first bit that was clocked with the falling edge of the
231      * the last command data clock
232      */
233
234     NVRAM_CMD(NR_READ + addr);
235
236     /*
237      * Now read the rest of the bits, the next bit read is D1, then D2,
238      * and so on
239      */
240
241     val = 0;
242     for (i=0; i<16; i++) {
243         NVRAM_CLKIN(t);
244         val <<= 1;
245         val |= t;
246     }
247     NVRAM_CLR_CE;
248
249     CFG_OR(NVDI);
250     CFG_AND(~NV_MANUAL);
251
252     return(val);
253 }
254
255
256
257
258 /*******************************************************************
259  *
260  *      Local routine:  iph5526_nr_checksum
261  *      Purpose:        calculate novram checksum on fi->n_r.data
262  *      Description:
263  *
264  *      calculate a checksum for the novram on the image that is
265  *      currently in fi->n_r.data
266  *
267  *******************************************************************/
268
269 static void iph5526_nr_checksum(struct fc_info *fi)
270 {
271     int i;
272     unsigned short chksum = 0;
273
274     for (i=0; i<(IPH5526_NOVRAM_SIZE - 1); i++)
275         chksum += fi->n_r.data[i];
276
277     fi->n_r.data[i] = -chksum;
278 }