File: /usr/src/linux/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     }
279