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