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