1 /*
2  * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
3  * of PCI-SCSI IO processors.
4  *
5  * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
6  *
7  * This driver is derived from the Linux sym53c8xx driver.
8  * Copyright (C) 1998-2000  Gerard Roudier
9  *
10  * The sym53c8xx driver is derived from the ncr53c8xx driver that had been
11  * a port of the FreeBSD ncr driver to Linux-1.2.13.
12  *
13  * The original ncr driver has been written for 386bsd and FreeBSD by
14  *         Wolfgang Stanglmeier        <wolf@cologne.de>
15  *         Stefan Esser                <se@mi.Uni-Koeln.de>
16  * Copyright (C) 1994  Wolfgang Stanglmeier
17  *
18  * Other major contributions:
19  *
20  * NVRAM detection and reading.
21  * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
22  *
23  *-----------------------------------------------------------------------------
24  *
25  * Redistribution and use in source and binary forms, with or without
26  * modification, are permitted provided that the following conditions
27  * are met:
28  * 1. Redistributions of source code must retain the above copyright
29  *    notice, this list of conditions and the following disclaimer.
30  * 2. The name of the author may not be used to endorse or promote products
31  *    derived from this software without specific prior written permission.
32  *
33  * Where this Software is combined with software released under the terms of
34  * the GNU Public License ("GPL") and the terms of the GPL would require the
35  * combined work to also be released under the terms of the GPL, the terms
36  * and conditions of this License will apply in addition to those of the
37  * GPL with the exception of any terms or conditions of this License that
38  * conflict with, or are expressly prohibited by, the GPL.
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
44  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  */
52 
53 #ifdef __FreeBSD__
54 #include <dev/sym/sym_glue.h>
55 #else
56 #include "sym_glue.h"
57 #endif
58 
59 /*
60  *  Some poor and bogus sync table that refers to Tekram NVRAM layout.
61  */
62 #if SYM_CONF_NVRAM_SUPPORT
63 static u_char Tekram_sync[16] =
64 	{25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10};
65 #ifdef	SYM_CONF_DEBUG_NVRAM
66 static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120};
67 #endif
68 #endif
69 
70 /*
71  *  Get host setup from NVRAM.
72  */
sym_nvram_setup_host(hcb_p np,struct sym_nvram * nvram)73 void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram)
74 {
75 #if SYM_CONF_NVRAM_SUPPORT
76 	/*
77 	 *  Get parity checking, host ID, verbose mode
78 	 *  and miscellaneous host flags from NVRAM.
79 	 */
80 	switch(nvram->type) {
81 	case SYM_SYMBIOS_NVRAM:
82 		if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
83 			np->rv_scntl0  &= ~0x0a;
84 		np->myaddr = nvram->data.Symbios.host_id & 0x0f;
85 		if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
86 			np->verbose += 1;
87 		if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
88 			np->usrflags |= SYM_SCAN_TARGETS_HILO;
89 		if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
90 			np->usrflags |= SYM_AVOID_BUS_RESET;
91 		break;
92 	case SYM_TEKRAM_NVRAM:
93 		np->myaddr = nvram->data.Tekram.host_id & 0x0f;
94 		break;
95 	default:
96 		break;
97 	}
98 #endif
99 }
100 
101 /*
102  *  Get target setup from NVRAM.
103  */
104 #if SYM_CONF_NVRAM_SUPPORT
105 static void sym_Symbios_setup_target(hcb_p np,int target, Symbios_nvram *nvram);
106 static void sym_Tekram_setup_target(hcb_p np,int target, Tekram_nvram *nvram);
107 #endif
108 
sym_nvram_setup_target(hcb_p np,int target,struct sym_nvram * nvp)109 void sym_nvram_setup_target (hcb_p np, int target, struct sym_nvram *nvp)
110 {
111 #if SYM_CONF_NVRAM_SUPPORT
112 	switch(nvp->type) {
113 	case SYM_SYMBIOS_NVRAM:
114 		sym_Symbios_setup_target (np, target, &nvp->data.Symbios);
115 		break;
116 	case SYM_TEKRAM_NVRAM:
117 		sym_Tekram_setup_target (np, target, &nvp->data.Tekram);
118 		break;
119 	default:
120 		break;
121 	}
122 #endif
123 }
124 
125 #if SYM_CONF_NVRAM_SUPPORT
126 /*
127  *  Get target set-up from Symbios format NVRAM.
128  */
129 static void
sym_Symbios_setup_target(hcb_p np,int target,Symbios_nvram * nvram)130 sym_Symbios_setup_target(hcb_p np, int target, Symbios_nvram *nvram)
131 {
132 	tcb_p tp = &np->target[target];
133 	Symbios_target *tn = &nvram->target[target];
134 
135 	tp->tinfo.user.period = tn->sync_period ? (tn->sync_period + 3) / 4 : 0;
136 	tp->tinfo.user.width  = tn->bus_width == 0x10 ? BUS_16_BIT : BUS_8_BIT;
137 	tp->usrtags =
138 		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SYM_SETUP_MAX_TAG : 0;
139 
140 	if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
141 		tp->usrflags &= ~SYM_DISC_ENABLED;
142 	if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
143 		tp->usrflags |= SYM_SCAN_BOOT_DISABLED;
144 	if (!(tn->flags & SYMBIOS_SCAN_LUNS))
145 		tp->usrflags |= SYM_SCAN_LUNS_DISABLED;
146 }
147 
148 /*
149  *  Get target set-up from Tekram format NVRAM.
150  */
151 static void
sym_Tekram_setup_target(hcb_p np,int target,Tekram_nvram * nvram)152 sym_Tekram_setup_target(hcb_p np, int target, Tekram_nvram *nvram)
153 {
154 	tcb_p tp = &np->target[target];
155 	struct Tekram_target *tn = &nvram->target[target];
156 	int i;
157 
158 	if (tn->flags & TEKRAM_SYNC_NEGO) {
159 		i = tn->sync_index & 0xf;
160 		tp->tinfo.user.period = Tekram_sync[i];
161 	}
162 
163 	tp->tinfo.user.width =
164 		(tn->flags & TEKRAM_WIDE_NEGO) ? BUS_16_BIT : BUS_8_BIT;
165 
166 	if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
167 		tp->usrtags = 2 << nvram->max_tags_index;
168 	}
169 
170 	if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
171 		tp->usrflags |= SYM_DISC_ENABLED;
172 
173 	/* If any device does not support parity, we will not use this option */
174 	if (!(tn->flags & TEKRAM_PARITY_CHECK))
175 		np->rv_scntl0  &= ~0x0a; /* SCSI parity checking disabled */
176 }
177 
178 #ifdef	SYM_CONF_DEBUG_NVRAM
179 /*
180  *  Dump Symbios format NVRAM for debugging purpose.
181  */
sym_display_Symbios_nvram(sdev_p np,Symbios_nvram * nvram)182 static void sym_display_Symbios_nvram(sdev_p np, Symbios_nvram *nvram)
183 {
184 	int i;
185 
186 	/* display Symbios nvram host data */
187 	printf("%s: HOST ID=%d%s%s%s%s%s%s\n",
188 		sym_name(np), nvram->host_id & 0x0f,
189 		(nvram->flags  & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
190 		(nvram->flags  & SYMBIOS_PARITY_ENABLE)	? " PARITY"	:"",
191 		(nvram->flags  & SYMBIOS_VERBOSE_MSGS)	? " VERBOSE"	:"",
192 		(nvram->flags  & SYMBIOS_CHS_MAPPING)	? " CHS_ALT"	:"",
193 		(nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET"	:"",
194 		(nvram->flags1 & SYMBIOS_SCAN_HI_LO)	? " HI_LO"	:"");
195 
196 	/* display Symbios nvram drive data */
197 	for (i = 0 ; i < 15 ; i++) {
198 		struct Symbios_target *tn = &nvram->target[i];
199 		printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
200 		sym_name(np), i,
201 		(tn->flags & SYMBIOS_DISCONNECT_ENABLE)	? " DISC"	: "",
202 		(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)	? " SCAN_BOOT"	: "",
203 		(tn->flags & SYMBIOS_SCAN_LUNS)		? " SCAN_LUNS"	: "",
204 		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ"	: "",
205 		tn->bus_width,
206 		tn->sync_period / 4,
207 		tn->timeout);
208 	}
209 }
210 
211 /*
212  *  Dump TEKRAM format NVRAM for debugging purpose.
213  */
sym_display_Tekram_nvram(sdev_p np,Tekram_nvram * nvram)214 static void sym_display_Tekram_nvram(sdev_p np, Tekram_nvram *nvram)
215 {
216 	int i, tags, boot_delay;
217 	char *rem;
218 
219 	/* display Tekram nvram host data */
220 	tags = 2 << nvram->max_tags_index;
221 	boot_delay = 0;
222 	if (nvram->boot_delay_index < 6)
223 		boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
224 	switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
225 	default:
226 	case 0:	rem = "";			break;
227 	case 1: rem = " REMOVABLE=boot device";	break;
228 	case 2: rem = " REMOVABLE=all";		break;
229 	}
230 
231 	printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
232 		sym_name(np), nvram->host_id & 0x0f,
233 		(nvram->flags1 & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
234 		(nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"",
235 		(nvram->flags & TEKRAM_DRIVES_SUP_1GB)	? " >1GB"	:"",
236 		(nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET"	:"",
237 		(nvram->flags & TEKRAM_ACTIVE_NEGATION)	? " ACT_NEG"	:"",
238 		(nvram->flags & TEKRAM_IMMEDIATE_SEEK)	? " IMM_SEEK"	:"",
239 		(nvram->flags & TEKRAM_SCAN_LUNS)	? " SCAN_LUNS"	:"",
240 		(nvram->flags1 & TEKRAM_F2_F6_ENABLED)	? " F2_F6"	:"",
241 		rem, boot_delay, tags);
242 
243 	/* display Tekram nvram drive data */
244 	for (i = 0; i <= 15; i++) {
245 		int sync, j;
246 		struct Tekram_target *tn = &nvram->target[i];
247 		j = tn->sync_index & 0xf;
248 		sync = Tekram_sync[j];
249 		printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
250 		sym_name(np), i,
251 		(tn->flags & TEKRAM_PARITY_CHECK)	? " PARITY"	: "",
252 		(tn->flags & TEKRAM_SYNC_NEGO)		? " SYNC"	: "",
253 		(tn->flags & TEKRAM_DISCONNECT_ENABLE)	? " DISC"	: "",
254 		(tn->flags & TEKRAM_START_CMD)		? " START"	: "",
255 		(tn->flags & TEKRAM_TAGGED_COMMANDS)	? " TCQ"	: "",
256 		(tn->flags & TEKRAM_WIDE_NEGO)		? " WIDE"	: "",
257 		sync);
258 	}
259 }
260 #endif	/* SYM_CONF_DEBUG_NVRAM */
261 #endif	/* SYM_CONF_NVRAM_SUPPORT */
262 
263 
264 /*
265  *  Try reading Symbios or Tekram NVRAM
266  */
267 #if SYM_CONF_NVRAM_SUPPORT
268 static int sym_read_Symbios_nvram (sdev_p np, Symbios_nvram *nvram);
269 static int sym_read_Tekram_nvram  (sdev_p np, Tekram_nvram *nvram);
270 #endif
271 
sym_read_nvram(sdev_p np,struct sym_nvram * nvp)272 int sym_read_nvram (sdev_p np, struct sym_nvram *nvp)
273 {
274 #if SYM_CONF_NVRAM_SUPPORT
275 	/*
276 	 *  Try to read SYMBIOS nvram.
277 	 *  Try to read TEKRAM nvram if Symbios nvram not found.
278 	 */
279 	if	(SYM_SETUP_SYMBIOS_NVRAM &&
280 		 !sym_read_Symbios_nvram (np, &nvp->data.Symbios)) {
281 		nvp->type = SYM_SYMBIOS_NVRAM;
282 #ifdef SYM_CONF_DEBUG_NVRAM
283 		sym_display_Symbios_nvram(np, &nvp->data.Symbios);
284 #endif
285 	}
286 	else if	(SYM_SETUP_TEKRAM_NVRAM &&
287 		 !sym_read_Tekram_nvram (np, &nvp->data.Tekram)) {
288 		nvp->type = SYM_TEKRAM_NVRAM;
289 #ifdef SYM_CONF_DEBUG_NVRAM
290 		sym_display_Tekram_nvram(np, &nvp->data.Tekram);
291 #endif
292 	}
293 	else
294 		nvp->type = 0;
295 #else
296 	nvp->type = 0;
297 #endif
298 	return nvp->type;
299 }
300 
301 
302 #if SYM_CONF_NVRAM_SUPPORT
303 /*
304  *  24C16 EEPROM reading.
305  *
306  *  GPOI0 - data in/data out
307  *  GPIO1 - clock
308  *  Symbios NVRAM wiring now also used by Tekram.
309  */
310 
311 #define SET_BIT 0
312 #define CLR_BIT 1
313 #define SET_CLK 2
314 #define CLR_CLK 3
315 
316 /*
317  *  Set/clear data/clock bit in GPIO0
318  */
S24C16_set_bit(sdev_p np,u_char write_bit,u_char * gpreg,int bit_mode)319 static void S24C16_set_bit(sdev_p np, u_char write_bit, u_char *gpreg,
320 			  int bit_mode)
321 {
322 	UDELAY (5);
323 	switch (bit_mode){
324 	case SET_BIT:
325 		*gpreg |= write_bit;
326 		break;
327 	case CLR_BIT:
328 		*gpreg &= 0xfe;
329 		break;
330 	case SET_CLK:
331 		*gpreg |= 0x02;
332 		break;
333 	case CLR_CLK:
334 		*gpreg &= 0xfd;
335 		break;
336 
337 	}
338 	OUTB (nc_gpreg, *gpreg);
339 	UDELAY (5);
340 }
341 
342 /*
343  *  Send START condition to NVRAM to wake it up.
344  */
S24C16_start(sdev_p np,u_char * gpreg)345 static void S24C16_start(sdev_p np, u_char *gpreg)
346 {
347 	S24C16_set_bit(np, 1, gpreg, SET_BIT);
348 	S24C16_set_bit(np, 0, gpreg, SET_CLK);
349 	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
350 	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
351 }
352 
353 /*
354  *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
355  */
S24C16_stop(sdev_p np,u_char * gpreg)356 static void S24C16_stop(sdev_p np, u_char *gpreg)
357 {
358 	S24C16_set_bit(np, 0, gpreg, SET_CLK);
359 	S24C16_set_bit(np, 1, gpreg, SET_BIT);
360 }
361 
362 /*
363  *  Read or write a bit to the NVRAM,
364  *  read if GPIO0 input else write if GPIO0 output
365  */
S24C16_do_bit(sdev_p np,u_char * read_bit,u_char write_bit,u_char * gpreg)366 static void S24C16_do_bit(sdev_p np, u_char *read_bit, u_char write_bit,
367 			 u_char *gpreg)
368 {
369 	S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
370 	S24C16_set_bit(np, 0, gpreg, SET_CLK);
371 	if (read_bit)
372 		*read_bit = INB (nc_gpreg);
373 	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
374 	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
375 }
376 
377 /*
378  *  Output an ACK to the NVRAM after reading,
379  *  change GPIO0 to output and when done back to an input
380  */
S24C16_write_ack(sdev_p np,u_char write_bit,u_char * gpreg,u_char * gpcntl)381 static void S24C16_write_ack(sdev_p np, u_char write_bit, u_char *gpreg,
382 			    u_char *gpcntl)
383 {
384 	OUTB (nc_gpcntl, *gpcntl & 0xfe);
385 	S24C16_do_bit(np, 0, write_bit, gpreg);
386 	OUTB (nc_gpcntl, *gpcntl);
387 }
388 
389 /*
390  *  Input an ACK from NVRAM after writing,
391  *  change GPIO0 to input and when done back to an output
392  */
S24C16_read_ack(sdev_p np,u_char * read_bit,u_char * gpreg,u_char * gpcntl)393 static void S24C16_read_ack(sdev_p np, u_char *read_bit, u_char *gpreg,
394 			   u_char *gpcntl)
395 {
396 	OUTB (nc_gpcntl, *gpcntl | 0x01);
397 	S24C16_do_bit(np, read_bit, 1, gpreg);
398 	OUTB (nc_gpcntl, *gpcntl);
399 }
400 
401 /*
402  *  WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
403  *  GPIO0 must already be set as an output
404  */
S24C16_write_byte(sdev_p np,u_char * ack_data,u_char write_data,u_char * gpreg,u_char * gpcntl)405 static void S24C16_write_byte(sdev_p np, u_char *ack_data, u_char write_data,
406 			     u_char *gpreg, u_char *gpcntl)
407 {
408 	int x;
409 
410 	for (x = 0; x < 8; x++)
411 		S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
412 
413 	S24C16_read_ack(np, ack_data, gpreg, gpcntl);
414 }
415 
416 /*
417  *  READ a byte from the NVRAM and then send an ACK to say we have got it,
418  *  GPIO0 must already be set as an input
419  */
S24C16_read_byte(sdev_p np,u_char * read_data,u_char ack_data,u_char * gpreg,u_char * gpcntl)420 static void S24C16_read_byte(sdev_p np, u_char *read_data, u_char ack_data,
421 			    u_char *gpreg, u_char *gpcntl)
422 {
423 	int x;
424 	u_char read_bit;
425 
426 	*read_data = 0;
427 	for (x = 0; x < 8; x++) {
428 		S24C16_do_bit(np, &read_bit, 1, gpreg);
429 		*read_data |= ((read_bit & 0x01) << (7 - x));
430 	}
431 
432 	S24C16_write_ack(np, ack_data, gpreg, gpcntl);
433 }
434 
435 /*
436  *  Read 'len' bytes starting at 'offset'.
437  */
sym_read_S24C16_nvram(sdev_p np,int offset,u_char * data,int len)438 static int sym_read_S24C16_nvram (sdev_p np, int offset, u_char *data, int len)
439 {
440 	u_char	gpcntl, gpreg;
441 	u_char	old_gpcntl, old_gpreg;
442 	u_char	ack_data;
443 	int	retv = 1;
444 	int	x;
445 
446 	/* save current state of GPCNTL and GPREG */
447 	old_gpreg	= INB (nc_gpreg);
448 	old_gpcntl	= INB (nc_gpcntl);
449 	gpcntl		= old_gpcntl & 0x1c;
450 
451 	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
452 	OUTB (nc_gpreg,  old_gpreg);
453 	OUTB (nc_gpcntl, gpcntl);
454 
455 	/* this is to set NVRAM into a known state with GPIO0/1 both low */
456 	gpreg = old_gpreg;
457 	S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
458 	S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
459 
460 	/* now set NVRAM inactive with GPIO0/1 both high */
461 	S24C16_stop(np, &gpreg);
462 
463 	/* activate NVRAM */
464 	S24C16_start(np, &gpreg);
465 
466 	/* write device code and random address MSB */
467 	S24C16_write_byte(np, &ack_data,
468 		0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
469 	if (ack_data & 0x01)
470 		goto out;
471 
472 	/* write random address LSB */
473 	S24C16_write_byte(np, &ack_data,
474 		offset & 0xff, &gpreg, &gpcntl);
475 	if (ack_data & 0x01)
476 		goto out;
477 
478 	/* regenerate START state to set up for reading */
479 	S24C16_start(np, &gpreg);
480 
481 	/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
482 	S24C16_write_byte(np, &ack_data,
483 		0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
484 	if (ack_data & 0x01)
485 		goto out;
486 
487 	/* now set up GPIO0 for inputting data */
488 	gpcntl |= 0x01;
489 	OUTB (nc_gpcntl, gpcntl);
490 
491 	/* input all requested data - only part of total NVRAM */
492 	for (x = 0; x < len; x++)
493 		S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
494 
495 	/* finally put NVRAM back in inactive mode */
496 	gpcntl &= 0xfe;
497 	OUTB (nc_gpcntl, gpcntl);
498 	S24C16_stop(np, &gpreg);
499 	retv = 0;
500 out:
501 	/* return GPIO0/1 to original states after having accessed NVRAM */
502 	OUTB (nc_gpcntl, old_gpcntl);
503 	OUTB (nc_gpreg,  old_gpreg);
504 
505 	return retv;
506 }
507 
508 #undef SET_BIT
509 #undef CLR_BIT
510 #undef SET_CLK
511 #undef CLR_CLK
512 
513 /*
514  *  Try reading Symbios NVRAM.
515  *  Return 0 if OK.
516  */
sym_read_Symbios_nvram(sdev_p np,Symbios_nvram * nvram)517 static int sym_read_Symbios_nvram (sdev_p np, Symbios_nvram *nvram)
518 {
519 	static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
520 	u_char *data = (u_char *) nvram;
521 	int len  = sizeof(*nvram);
522 	u_short	csum;
523 	int x;
524 
525 	/* probe the 24c16 and read the SYMBIOS 24c16 area */
526 	if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
527 		return 1;
528 
529 	/* check valid NVRAM signature, verify byte count and checksum */
530 	if (nvram->type != 0 ||
531 	    bcmp(nvram->trailer, Symbios_trailer, 6) ||
532 	    nvram->byte_count != len - 12)
533 		return 1;
534 
535 	/* verify checksum */
536 	for (x = 6, csum = 0; x < len - 6; x++)
537 		csum += data[x];
538 	if (csum != nvram->checksum)
539 		return 1;
540 
541 	return 0;
542 }
543 
544 /*
545  *  93C46 EEPROM reading.
546  *
547  *  GPOI0 - data in
548  *  GPIO1 - data out
549  *  GPIO2 - clock
550  *  GPIO4 - chip select
551  *
552  *  Used by Tekram.
553  */
554 
555 /*
556  *  Pulse clock bit in GPIO0
557  */
T93C46_Clk(sdev_p np,u_char * gpreg)558 static void T93C46_Clk(sdev_p np, u_char *gpreg)
559 {
560 	OUTB (nc_gpreg, *gpreg | 0x04);
561 	UDELAY (2);
562 	OUTB (nc_gpreg, *gpreg);
563 }
564 
565 /*
566  *  Read bit from NVRAM
567  */
T93C46_Read_Bit(sdev_p np,u_char * read_bit,u_char * gpreg)568 static void T93C46_Read_Bit(sdev_p np, u_char *read_bit, u_char *gpreg)
569 {
570 	UDELAY (2);
571 	T93C46_Clk(np, gpreg);
572 	*read_bit = INB (nc_gpreg);
573 }
574 
575 /*
576  *  Write bit to GPIO0
577  */
T93C46_Write_Bit(sdev_p np,u_char write_bit,u_char * gpreg)578 static void T93C46_Write_Bit(sdev_p np, u_char write_bit, u_char *gpreg)
579 {
580 	if (write_bit & 0x01)
581 		*gpreg |= 0x02;
582 	else
583 		*gpreg &= 0xfd;
584 
585 	*gpreg |= 0x10;
586 
587 	OUTB (nc_gpreg, *gpreg);
588 	UDELAY (2);
589 
590 	T93C46_Clk(np, gpreg);
591 }
592 
593 /*
594  *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
595  */
T93C46_Stop(sdev_p np,u_char * gpreg)596 static void T93C46_Stop(sdev_p np, u_char *gpreg)
597 {
598 	*gpreg &= 0xef;
599 	OUTB (nc_gpreg, *gpreg);
600 	UDELAY (2);
601 
602 	T93C46_Clk(np, gpreg);
603 }
604 
605 /*
606  *  Send read command and address to NVRAM
607  */
T93C46_Send_Command(sdev_p np,u_short write_data,u_char * read_bit,u_char * gpreg)608 static void T93C46_Send_Command(sdev_p np, u_short write_data,
609 				u_char *read_bit, u_char *gpreg)
610 {
611 	int x;
612 
613 	/* send 9 bits, start bit (1), command (2), address (6)  */
614 	for (x = 0; x < 9; x++)
615 		T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
616 
617 	*read_bit = INB (nc_gpreg);
618 }
619 
620 /*
621  *  READ 2 bytes from the NVRAM
622  */
T93C46_Read_Word(sdev_p np,u_short * nvram_data,u_char * gpreg)623 static void T93C46_Read_Word(sdev_p np, u_short *nvram_data, u_char *gpreg)
624 {
625 	int x;
626 	u_char read_bit;
627 
628 	*nvram_data = 0;
629 	for (x = 0; x < 16; x++) {
630 		T93C46_Read_Bit(np, &read_bit, gpreg);
631 
632 		if (read_bit & 0x01)
633 			*nvram_data |=  (0x01 << (15 - x));
634 		else
635 			*nvram_data &= ~(0x01 << (15 - x));
636 	}
637 }
638 
639 /*
640  *  Read Tekram NvRAM data.
641  */
T93C46_Read_Data(sdev_p np,u_short * data,int len,u_char * gpreg)642 static int T93C46_Read_Data(sdev_p np, u_short *data,int len,u_char *gpreg)
643 {
644 	u_char	read_bit;
645 	int	x;
646 
647 	for (x = 0; x < len; x++)  {
648 
649 		/* output read command and address */
650 		T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
651 		if (read_bit & 0x01)
652 			return 1; /* Bad */
653 		T93C46_Read_Word(np, &data[x], gpreg);
654 		T93C46_Stop(np, gpreg);
655 	}
656 
657 	return 0;
658 }
659 
660 /*
661  *  Try reading 93C46 Tekram NVRAM.
662  */
sym_read_T93C46_nvram(sdev_p np,Tekram_nvram * nvram)663 static int sym_read_T93C46_nvram (sdev_p np, Tekram_nvram *nvram)
664 {
665 	u_char gpcntl, gpreg;
666 	u_char old_gpcntl, old_gpreg;
667 	int retv = 1;
668 
669 	/* save current state of GPCNTL and GPREG */
670 	old_gpreg	= INB (nc_gpreg);
671 	old_gpcntl	= INB (nc_gpcntl);
672 
673 	/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
674 	   1/2/4 out */
675 	gpreg = old_gpreg & 0xe9;
676 	OUTB (nc_gpreg, gpreg);
677 	gpcntl = (old_gpcntl & 0xe9) | 0x09;
678 	OUTB (nc_gpcntl, gpcntl);
679 
680 	/* input all of NVRAM, 64 words */
681 	retv = T93C46_Read_Data(np, (u_short *) nvram,
682 				sizeof(*nvram) / sizeof(short), &gpreg);
683 
684 	/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
685 	OUTB (nc_gpcntl, old_gpcntl);
686 	OUTB (nc_gpreg,  old_gpreg);
687 
688 	return retv;
689 }
690 
691 /*
692  *  Try reading Tekram NVRAM.
693  *  Return 0 if OK.
694  */
sym_read_Tekram_nvram(sdev_p np,Tekram_nvram * nvram)695 static int sym_read_Tekram_nvram (sdev_p np, Tekram_nvram *nvram)
696 {
697 	u_char *data = (u_char *) nvram;
698 	int len = sizeof(*nvram);
699 	u_short	csum;
700 	int x;
701 
702 	switch (np->device_id) {
703 	case PCI_ID_SYM53C885:
704 	case PCI_ID_SYM53C895:
705 	case PCI_ID_SYM53C896:
706 		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
707 					  data, len);
708 		break;
709 	case PCI_ID_SYM53C875:
710 		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
711 					  data, len);
712 		if (!x)
713 			break;
714 	default:
715 		x = sym_read_T93C46_nvram(np, nvram);
716 		break;
717 	}
718 	if (x)
719 		return 1;
720 
721 	/* verify checksum */
722 	for (x = 0, csum = 0; x < len - 1; x += 2)
723 		csum += data[x] + (data[x+1] << 8);
724 	if (csum != 0x1234)
725 		return 1;
726 
727 	return 0;
728 }
729 
730 #endif	/* SYM_CONF_NVRAM_SUPPORT */
731