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 
iph5526_nr_do_init(struct fc_info * fi)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 
iph5526_nr_get(struct fc_info * fi,int addr)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 
iph5526_nr_checksum(struct fc_info * fi)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