Line data Source code
1 : /* $OpenBSD: aic7xxx_seeprom.c,v 1.7 2015/07/17 21:42:49 krw Exp $ */
2 : /* $NetBSD: aic7xxx_seeprom.c,v 1.8 2003/05/02 19:12:19 dyoung Exp $ */
3 :
4 : /*
5 : * Product specific probe and attach routines for:
6 : * 3940, 2940, aic7895, aic7890, aic7880,
7 : * aic7870, aic7860 and aic7850 SCSI controllers
8 : *
9 : * Copyright (c) 1994-2001 Justin T. Gibbs.
10 : * Copyright (c) 2000-2001 Adaptec Inc.
11 : * All rights reserved.
12 : *
13 : * Redistribution and use in source and binary forms, with or without
14 : * modification, are permitted provided that the following conditions
15 : * are met:
16 : * 1. Redistributions of source code must retain the above copyright
17 : * notice, this list of conditions, and the following disclaimer,
18 : * without modification.
19 : * 2. Redistributions in binary form must reproduce at minimum a disclaimer
20 : * substantially similar to the "NO WARRANTY" disclaimer below
21 : * ("Disclaimer") and any redistribution must be conditioned upon
22 : * including a substantially similar Disclaimer requirement for further
23 : * binary redistribution.
24 : * 3. Neither the names of the above-listed copyright holders nor the names
25 : * of any contributors may be used to endorse or promote products derived
26 : * from this software without specific prior written permission.
27 : *
28 : * Alternatively, this software may be distributed under the terms of the
29 : * GNU General Public License ("GPL") version 2 as published by the Free
30 : * Software Foundation.
31 : *
32 : * NO WARRANTY
33 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
34 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
36 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
37 : * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
42 : * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 : * POSSIBILITY OF SUCH DAMAGES.
44 : *
45 : * This file was originally split off from the PCI code by
46 : * Jason Thorpe <thorpej@netbsd.org>. This version was split off
47 : * from the FreeBSD source file aic7xxx_pci.c by Frank van der Linden
48 : * <fvdl@netbsd.org>
49 : *
50 : * $Id: aic7xxx_seeprom.c,v 1.7 2015/07/17 21:42:49 krw Exp $
51 : *
52 : * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.22 2003/01/20 20:44:55 gibbs Exp $
53 : */
54 :
55 : #include <sys/param.h>
56 : #include <sys/systm.h>
57 : #include <sys/malloc.h>
58 : #include <sys/kernel.h>
59 : #include <sys/queue.h>
60 : #include <sys/device.h>
61 : #include <sys/reboot.h> /* for AB_* needed by bootverbose */
62 :
63 : #include <machine/intr.h>
64 :
65 : #include <scsi/scsi_all.h>
66 : #include <scsi/scsiconf.h>
67 :
68 : #include <dev/ic/aic7xxx_openbsd.h>
69 : #include <dev/ic/aic7xxx_inline.h>
70 :
71 : #include <dev/ic/smc93cx6var.h>
72 :
73 : #define DEVCONFIG 0x40
74 : #define STPWLEVEL 0x00000002
75 :
76 : static void configure_termination(struct ahc_softc *,
77 : struct seeprom_descriptor *, u_int, u_int *);
78 : static int verify_seeprom_cksum(struct seeprom_config *sc);
79 :
80 : static void ahc_new_term_detect(struct ahc_softc *, int *, int *, int *,
81 : int *, int *);
82 : static void aic787X_cable_detect(struct ahc_softc *, int *, int *, int *,
83 : int *);
84 : static void aic785X_cable_detect(struct ahc_softc *, int *, int *, int *);
85 : static void write_brdctl(struct ahc_softc *, u_int8_t);
86 : static u_int8_t read_brdctl(struct ahc_softc *);
87 : static void ahc_parse_pci_eeprom(struct ahc_softc *, struct seeprom_config *);
88 :
89 : /*
90 : * Check the external port logic for a serial eeprom
91 : * and termination/cable detection contrls.
92 : */
93 : void
94 0 : ahc_check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
95 : {
96 0 : struct seeprom_descriptor sd;
97 : struct seeprom_config *sc;
98 : int have_seeprom;
99 : int have_autoterm;
100 :
101 0 : sd.sd_tag = ahc->tag;
102 0 : sd.sd_bsh = ahc->bsh;
103 0 : sd.sd_regsize = 1;
104 0 : sd.sd_control_offset = SEECTL;
105 0 : sd.sd_status_offset = SEECTL;
106 0 : sd.sd_dataout_offset = SEECTL;
107 0 : sc = ahc->seep_config;
108 :
109 : /*
110 : * For some multi-channel devices, the c46 is simply too
111 : * small to work. For the other controller types, we can
112 : * get our information from either SEEPROM type. Set the
113 : * type to start our probe with accordingly.
114 : */
115 0 : if (ahc->flags & AHC_LARGE_SEEPROM)
116 0 : sd.sd_chip = C56_66;
117 : else
118 0 : sd.sd_chip = C46;
119 :
120 0 : sd.sd_MS = SEEMS;
121 0 : sd.sd_RDY = SEERDY;
122 0 : sd.sd_CS = SEECS;
123 0 : sd.sd_CK = SEECK;
124 0 : sd.sd_DO = SEEDO;
125 0 : sd.sd_DI = SEEDI;
126 :
127 0 : have_seeprom = ahc_acquire_seeprom(ahc, &sd);
128 0 : if (have_seeprom) {
129 :
130 : if (bootverbose)
131 : printf("%s: Reading SEEPROM...", ahc_name(ahc));
132 :
133 0 : for (;;) {
134 : u_int start_addr;
135 :
136 0 : start_addr = 32 * (ahc->channel - 'A');
137 0 : have_seeprom = read_seeprom(&sd, (uint16_t *)sc,
138 0 : start_addr,
139 : sizeof(*sc)/2);
140 :
141 0 : if (have_seeprom)
142 0 : have_seeprom = verify_seeprom_cksum(sc);
143 :
144 0 : if (have_seeprom != 0 || sd.sd_chip == C56_66) {
145 : if (bootverbose) {
146 : if (have_seeprom == 0)
147 : printf ("checksum error\n");
148 : else
149 : printf ("done.\n");
150 : }
151 0 : break;
152 : }
153 0 : sd.sd_chip = C56_66;
154 0 : }
155 0 : ahc_release_seeprom(&sd);
156 0 : }
157 :
158 0 : if (!have_seeprom) {
159 : /*
160 : * Pull scratch ram settings and treat them as
161 : * if they are the contents of an seeprom if
162 : * the 'ADPT' signature is found in SCB2.
163 : * We manually compose the data as 16bit values
164 : * to avoid endian issues.
165 : */
166 0 : ahc_outb(ahc, SCBPTR, 2);
167 0 : if (ahc_inb(ahc, SCB_BASE) == 'A'
168 0 : && ahc_inb(ahc, SCB_BASE + 1) == 'D'
169 0 : && ahc_inb(ahc, SCB_BASE + 2) == 'P'
170 0 : && ahc_inb(ahc, SCB_BASE + 3) == 'T') {
171 : uint16_t *sc_data;
172 : int i;
173 :
174 0 : sc_data = (uint16_t *)sc;
175 0 : for (i = 0; i < 32; i++, sc_data++) {
176 : int j;
177 :
178 0 : j = i * 2;
179 0 : *sc_data = ahc_inb(ahc, SRAM_BASE + j)
180 0 : | ahc_inb(ahc, SRAM_BASE + j + 1) << 8;
181 : }
182 0 : have_seeprom = verify_seeprom_cksum(sc);
183 0 : if (have_seeprom)
184 0 : ahc->flags |= AHC_SCB_CONFIG_USED;
185 0 : }
186 : /*
187 : * Clear any SCB parity errors in case this data and
188 : * its associated parity was not initialized by the BIOS
189 : */
190 0 : ahc_outb(ahc, CLRINT, CLRPARERR);
191 0 : ahc_outb(ahc, CLRINT, CLRBRKADRINT);
192 0 : }
193 :
194 0 : if (!have_seeprom) {
195 : if (bootverbose)
196 : printf("%s: No SEEPROM available.\n", ahc_name(ahc));
197 0 : ahc->flags |= AHC_USEDEFAULTS | AHC_NO_BIOS_INIT;
198 0 : free(ahc->seep_config, M_DEVBUF, 0);
199 0 : ahc->seep_config = NULL;
200 : sc = NULL;
201 0 : } else {
202 0 : ahc_parse_pci_eeprom(ahc, sc);
203 : }
204 :
205 : /*
206 : * Cards that have the external logic necessary to talk to
207 : * a SEEPROM, are almost certain to have the remaining logic
208 : * necessary for auto-termination control. This assumption
209 : * hasn't failed yet...
210 : */
211 : have_autoterm = have_seeprom;
212 :
213 : /*
214 : * Some low-cost chips have SEEPROM and auto-term control built
215 : * in, instead of using a GAL. They can tell us directly
216 : * if the termination logic is enabled.
217 : */
218 0 : if ((ahc->features & AHC_SPIOCAP) != 0) {
219 0 : if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0)
220 0 : have_autoterm = FALSE;
221 : }
222 :
223 0 : if (have_autoterm) {
224 0 : ahc_acquire_seeprom(ahc, &sd);
225 0 : configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1);
226 0 : ahc_release_seeprom(&sd);
227 0 : } else if (have_seeprom) {
228 0 : *sxfrctl1 &= ~STPWEN;
229 0 : if ((sc->adapter_control & CFSTERM) != 0)
230 0 : *sxfrctl1 |= STPWEN;
231 : if (bootverbose)
232 : printf("%s: Low byte termination %sabled\n",
233 : ahc_name(ahc),
234 : (*sxfrctl1 & STPWEN) ? "en" : "dis");
235 : }
236 0 : }
237 :
238 : static void
239 0 : ahc_parse_pci_eeprom(struct ahc_softc *ahc, struct seeprom_config *sc)
240 : {
241 : /*
242 : * Put the data we've collected down into SRAM
243 : * where ahc_init will find it.
244 : */
245 : int i;
246 0 : int max_targ = sc->max_targets & CFMAXTARG;
247 : u_int scsi_conf;
248 : uint16_t discenable;
249 : uint16_t ultraenb;
250 :
251 : discenable = 0;
252 : ultraenb = 0;
253 0 : if ((sc->adapter_control & CFULTRAEN) != 0) {
254 : /*
255 : * Determine if this adapter has a "newstyle"
256 : * SEEPROM format.
257 : */
258 0 : for (i = 0; i < max_targ; i++) {
259 0 : if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) {
260 0 : ahc->flags |= AHC_NEWEEPROM_FMT;
261 0 : break;
262 : }
263 : }
264 : }
265 :
266 0 : for (i = 0; i < max_targ; i++) {
267 : u_int scsirate;
268 : uint16_t target_mask;
269 :
270 0 : target_mask = 0x01 << i;
271 0 : if (sc->device_flags[i] & CFDISC)
272 0 : discenable |= target_mask;
273 0 : if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) {
274 0 : if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0)
275 0 : ultraenb |= target_mask;
276 0 : } else if ((sc->adapter_control & CFULTRAEN) != 0) {
277 0 : ultraenb |= target_mask;
278 0 : }
279 0 : if ((sc->device_flags[i] & CFXFER) == 0x04
280 0 : && (ultraenb & target_mask) != 0) {
281 : /* Treat 10MHz as a non-ultra speed */
282 0 : sc->device_flags[i] &= ~CFXFER;
283 0 : ultraenb &= ~target_mask;
284 0 : }
285 0 : if ((ahc->features & AHC_ULTRA2) != 0) {
286 : u_int offset;
287 :
288 0 : if (sc->device_flags[i] & CFSYNCH)
289 0 : offset = MAX_OFFSET_ULTRA2;
290 : else
291 : offset = 0;
292 0 : ahc_outb(ahc, TARG_OFFSET + i, offset);
293 :
294 : /*
295 : * The ultra enable bits contain the
296 : * high bit of the ultra2 sync rate
297 : * field.
298 : */
299 0 : scsirate = (sc->device_flags[i] & CFXFER)
300 0 : | ((ultraenb & target_mask) ? 0x8 : 0x0);
301 0 : if (sc->device_flags[i] & CFWIDEB)
302 0 : scsirate |= WIDEXFER;
303 0 : } else {
304 0 : scsirate = (sc->device_flags[i] & CFXFER) << 4;
305 0 : if (sc->device_flags[i] & CFSYNCH)
306 0 : scsirate |= SOFS;
307 0 : if (sc->device_flags[i] & CFWIDEB)
308 0 : scsirate |= WIDEXFER;
309 : }
310 0 : ahc_outb(ahc, TARG_SCSIRATE + i, scsirate);
311 : }
312 0 : ahc->our_id = sc->brtime_id & CFSCSIID;
313 :
314 0 : scsi_conf = (ahc->our_id & 0x7);
315 0 : if (sc->adapter_control & CFSPARITY)
316 0 : scsi_conf |= ENSPCHK;
317 0 : if (sc->adapter_control & CFRESETB)
318 0 : scsi_conf |= RESET_SCSI;
319 :
320 0 : ahc->flags |= (sc->adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
321 :
322 0 : if (sc->bios_control & CFEXTEND)
323 0 : ahc->flags |= AHC_EXTENDED_TRANS_A;
324 :
325 0 : if (sc->bios_control & CFBIOSEN)
326 0 : ahc->flags |= AHC_BIOS_ENABLED;
327 0 : if (ahc->features & AHC_ULTRA
328 0 : && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
329 : /* Should we enable Ultra mode? */
330 0 : if (!(sc->adapter_control & CFULTRAEN))
331 : /* Treat us as a non-ultra card */
332 0 : ultraenb = 0;
333 : }
334 :
335 0 : if (sc->signature == CFSIGNATURE
336 0 : || sc->signature == CFSIGNATURE2) {
337 : uint32_t devconfig;
338 :
339 : /* Honor the STPWLEVEL settings */
340 0 : devconfig = pci_conf_read(ahc->bd->pc, ahc->bd->tag, DEVCONFIG);
341 0 : devconfig &= ~STPWLEVEL;
342 0 : if ((sc->bios_control & CFSTPWLEVEL) != 0)
343 0 : devconfig |= STPWLEVEL;
344 0 : pci_conf_write(ahc->bd->pc, ahc->bd->tag, DEVCONFIG, devconfig);
345 0 : }
346 : /* Set SCSICONF info */
347 0 : ahc_outb(ahc, SCSICONF, scsi_conf);
348 0 : ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
349 0 : ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
350 0 : ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff);
351 0 : ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff);
352 0 : }
353 :
354 : static void
355 0 : configure_termination(struct ahc_softc *ahc,
356 : struct seeprom_descriptor *sd,
357 : u_int adapter_control,
358 : u_int *sxfrctl1)
359 : {
360 : uint8_t brddat;
361 :
362 : brddat = 0;
363 :
364 : /*
365 : * Update the settings in sxfrctl1 to match the
366 : * termination settings
367 : */
368 0 : *sxfrctl1 = 0;
369 :
370 : /*
371 : * SEECS must be on for the GALS to latch
372 : * the data properly. Be sure to leave MS
373 : * on or we will release the seeprom.
374 : */
375 0 : SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS);
376 0 : if ((adapter_control & CFAUTOTERM) != 0
377 0 : || (ahc->features & AHC_NEW_TERMCTL) != 0) {
378 0 : int internal50_present;
379 0 : int internal68_present;
380 0 : int externalcable_present;
381 0 : int eeprom_present;
382 0 : int enableSEC_low;
383 0 : int enableSEC_high;
384 0 : int enablePRI_low;
385 0 : int enablePRI_high;
386 : int sum;
387 :
388 0 : enableSEC_low = 0;
389 0 : enableSEC_high = 0;
390 0 : enablePRI_low = 0;
391 0 : enablePRI_high = 0;
392 0 : if ((ahc->features & AHC_NEW_TERMCTL) != 0) {
393 0 : ahc_new_term_detect(ahc, &enableSEC_low,
394 : &enableSEC_high,
395 : &enablePRI_low,
396 : &enablePRI_high,
397 : &eeprom_present);
398 0 : if ((adapter_control & CFSEAUTOTERM) == 0) {
399 : if (bootverbose)
400 : printf("%s: Manual SE Termination\n",
401 : ahc_name(ahc));
402 0 : enableSEC_low = (adapter_control & CFSELOWTERM);
403 0 : enableSEC_high =
404 0 : (adapter_control & CFSEHIGHTERM);
405 0 : }
406 0 : if ((adapter_control & CFAUTOTERM) == 0) {
407 : if (bootverbose)
408 : printf("%s: Manual LVD Termination\n",
409 : ahc_name(ahc));
410 0 : enablePRI_low = (adapter_control & CFSTERM);
411 0 : enablePRI_high = (adapter_control & CFWSTERM);
412 0 : }
413 : /* Make the table calculations below happy */
414 0 : internal50_present = 0;
415 0 : internal68_present = 1;
416 0 : externalcable_present = 1;
417 0 : } else if ((ahc->features & AHC_SPIOCAP) != 0) {
418 0 : aic785X_cable_detect(ahc, &internal50_present,
419 : &externalcable_present,
420 : &eeprom_present);
421 : /* Can never support a wide connector. */
422 0 : internal68_present = 0;
423 0 : } else {
424 0 : aic787X_cable_detect(ahc, &internal50_present,
425 : &internal68_present,
426 : &externalcable_present,
427 : &eeprom_present);
428 : }
429 :
430 0 : if ((ahc->features & AHC_WIDE) == 0)
431 0 : internal68_present = 0;
432 :
433 : if (bootverbose
434 : && (ahc->features & AHC_ULTRA2) == 0) {
435 : printf("%s: internal 50 cable %s present",
436 : ahc_name(ahc),
437 : internal50_present ? "is":"not");
438 :
439 : if ((ahc->features & AHC_WIDE) != 0)
440 : printf(", internal 68 cable %s present",
441 : internal68_present ? "is":"not");
442 : printf("\n%s: external cable %s present\n",
443 : ahc_name(ahc),
444 : externalcable_present ? "is":"not");
445 : }
446 : if (bootverbose)
447 : printf("%s: BIOS eeprom %s present\n",
448 : ahc_name(ahc), eeprom_present ? "is" : "not");
449 :
450 0 : if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) {
451 : /*
452 : * The 50 pin connector is a separate bus,
453 : * so force it to always be terminated.
454 : * In the future, perform current sensing
455 : * to determine if we are in the middle of
456 : * a properly terminated bus.
457 : */
458 0 : internal50_present = 0;
459 0 : }
460 :
461 : /*
462 : * Now set the termination based on what
463 : * we found.
464 : * Flash Enable = BRDDAT7
465 : * Secondary High Term Enable = BRDDAT6
466 : * Secondary Low Term Enable = BRDDAT5 (7890)
467 : * Primary High Term Enable = BRDDAT4 (7890)
468 : */
469 0 : if ((ahc->features & AHC_ULTRA2) == 0
470 0 : && (internal50_present != 0)
471 0 : && (internal68_present != 0)
472 0 : && (externalcable_present != 0)) {
473 0 : printf("%s: Illegal cable configuration!!. "
474 : "Only two connectors on the "
475 : "adapter may be used at a "
476 0 : "time!\n", ahc_name(ahc));
477 :
478 : /*
479 : * Pretend there are no cables in the hope
480 : * that having all of the termination on
481 : * gives us a more stable bus.
482 : */
483 0 : internal50_present = 0;
484 0 : internal68_present = 0;
485 0 : externalcable_present = 0;
486 0 : }
487 :
488 0 : if ((ahc->features & AHC_WIDE) != 0
489 0 : && ((externalcable_present == 0)
490 0 : || (internal68_present == 0)
491 0 : || (enableSEC_high != 0))) {
492 : brddat |= BRDDAT6;
493 : if (bootverbose) {
494 : if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
495 : printf("%s: 68 pin termination "
496 : "Enabled\n", ahc_name(ahc));
497 : else
498 : printf("%s: %sHigh byte termination "
499 : "Enabled\n", ahc_name(ahc),
500 : enableSEC_high ? "Secondary "
501 : : "");
502 : }
503 0 : }
504 :
505 0 : sum = internal50_present + internal68_present
506 0 : + externalcable_present;
507 0 : if (sum < 2 || (enableSEC_low != 0)) {
508 0 : if ((ahc->features & AHC_ULTRA2) != 0)
509 0 : brddat |= BRDDAT5;
510 : else
511 0 : *sxfrctl1 |= STPWEN;
512 : if (bootverbose) {
513 : if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
514 : printf("%s: 50 pin termination "
515 : "Enabled\n", ahc_name(ahc));
516 : else
517 : printf("%s: %sLow byte termination "
518 : "Enabled\n", ahc_name(ahc),
519 : enableSEC_low ? "Secondary "
520 : : "");
521 : }
522 : }
523 :
524 0 : if (enablePRI_low != 0) {
525 0 : *sxfrctl1 |= STPWEN;
526 : if (bootverbose)
527 : printf("%s: Primary Low Byte termination "
528 : "Enabled\n", ahc_name(ahc));
529 0 : }
530 :
531 : /*
532 : * Setup STPWEN before setting up the rest of
533 : * the termination per the tech note on the U160 cards.
534 : */
535 0 : ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
536 :
537 0 : if (enablePRI_high != 0) {
538 0 : brddat |= BRDDAT4;
539 : if (bootverbose)
540 : printf("%s: Primary High Byte "
541 : "termination Enabled\n",
542 : ahc_name(ahc));
543 0 : }
544 :
545 0 : write_brdctl(ahc, brddat);
546 :
547 0 : } else {
548 0 : if ((adapter_control & CFSTERM) != 0) {
549 0 : *sxfrctl1 |= STPWEN;
550 :
551 : if (bootverbose)
552 : printf("%s: %sLow byte termination Enabled\n",
553 : ahc_name(ahc),
554 : (ahc->features & AHC_ULTRA2) ? "Primary "
555 : : "");
556 0 : }
557 :
558 0 : if ((adapter_control & CFWSTERM) != 0
559 0 : && (ahc->features & AHC_WIDE) != 0) {
560 : brddat |= BRDDAT6;
561 : if (bootverbose)
562 : printf("%s: %sHigh byte termination Enabled\n",
563 : ahc_name(ahc),
564 : (ahc->features & AHC_ULTRA2)
565 : ? "Secondary " : "");
566 0 : }
567 :
568 : /*
569 : * Setup STPWEN before setting up the rest of
570 : * the termination per the tech note on the U160 cards.
571 : */
572 0 : ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
573 :
574 0 : if ((ahc->features & AHC_WIDE) != 0)
575 0 : write_brdctl(ahc, brddat);
576 : }
577 0 : SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */
578 0 : }
579 :
580 : static void
581 0 : ahc_new_term_detect(struct ahc_softc *ahc, int *enableSEC_low,
582 : int *enableSEC_high, int *enablePRI_low,
583 : int *enablePRI_high, int *eeprom_present)
584 : {
585 : uint8_t brdctl;
586 :
587 : /*
588 : * BRDDAT7 = Eeprom
589 : * BRDDAT6 = Enable Secondary High Byte termination
590 : * BRDDAT5 = Enable Secondary Low Byte termination
591 : * BRDDAT4 = Enable Primary high byte termination
592 : * BRDDAT3 = Enable Primary low byte termination
593 : */
594 0 : brdctl = read_brdctl(ahc);
595 0 : *eeprom_present = brdctl & BRDDAT7;
596 0 : *enableSEC_high = (brdctl & BRDDAT6);
597 0 : *enableSEC_low = (brdctl & BRDDAT5);
598 0 : *enablePRI_high = (brdctl & BRDDAT4);
599 0 : *enablePRI_low = (brdctl & BRDDAT3);
600 0 : }
601 :
602 : static void
603 0 : aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
604 : int *internal68_present, int *externalcable_present,
605 : int *eeprom_present)
606 : {
607 : uint8_t brdctl;
608 :
609 : /*
610 : * First read the status of our cables.
611 : * Set the rom bank to 0 since the
612 : * bank setting serves as a multiplexor
613 : * for the cable detection logic.
614 : * BRDDAT5 controls the bank switch.
615 : */
616 0 : write_brdctl(ahc, 0);
617 :
618 : /*
619 : * Now read the state of the internal
620 : * connectors. BRDDAT6 is INT50 and
621 : * BRDDAT7 is INT68.
622 : */
623 0 : brdctl = read_brdctl(ahc);
624 0 : *internal50_present = (brdctl & BRDDAT6) ? 0 : 1;
625 0 : *internal68_present = (brdctl & BRDDAT7) ? 0 : 1;
626 :
627 : /*
628 : * Set the rom bank to 1 and determine
629 : * the other signals.
630 : */
631 0 : write_brdctl(ahc, BRDDAT5);
632 :
633 : /*
634 : * Now read the state of the external
635 : * connectors. BRDDAT6 is EXT68 and
636 : * BRDDAT7 is EPROMPS.
637 : */
638 0 : brdctl = read_brdctl(ahc);
639 0 : *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
640 0 : *eeprom_present = (brdctl & BRDDAT7) ? 1 : 0;
641 0 : }
642 :
643 : static void
644 0 : aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
645 : int *externalcable_present, int *eeprom_present)
646 : {
647 : uint8_t brdctl;
648 : uint8_t spiocap;
649 :
650 0 : spiocap = ahc_inb(ahc, SPIOCAP);
651 0 : spiocap &= ~SOFTCMDEN;
652 0 : spiocap |= EXT_BRDCTL;
653 0 : ahc_outb(ahc, SPIOCAP, spiocap);
654 0 : ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
655 0 : ahc_outb(ahc, BRDCTL, 0);
656 0 : brdctl = ahc_inb(ahc, BRDCTL);
657 0 : *internal50_present = (brdctl & BRDDAT5) ? 0 : 1;
658 0 : *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
659 :
660 0 : *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
661 0 : }
662 :
663 : int
664 0 : ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
665 : {
666 : int wait;
667 :
668 0 : if ((ahc->features & AHC_SPIOCAP) != 0
669 0 : && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0)
670 0 : return (0);
671 :
672 : /*
673 : * Request access of the memory port. When access is
674 : * granted, SEERDY will go high. We use a 1 second
675 : * timeout which should be near 1 second more than
676 : * is needed. Reason: after the chip reset, there
677 : * should be no contention.
678 : */
679 0 : SEEPROM_OUTB(sd, sd->sd_MS);
680 : wait = 1000; /* 1 second timeout in msec */
681 0 : while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) {
682 0 : aic_delay(1000); /* delay 1 msec */
683 : }
684 0 : if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) {
685 0 : SEEPROM_OUTB(sd, 0);
686 0 : return (0);
687 : }
688 0 : return(1);
689 0 : }
690 :
691 : void
692 0 : ahc_release_seeprom(struct seeprom_descriptor *sd)
693 : {
694 : /* Release access to the memory port and the serial EEPROM. */
695 0 : SEEPROM_OUTB(sd, 0);
696 0 : }
697 :
698 : static void
699 0 : write_brdctl(struct ahc_softc *ahc, uint8_t value)
700 : {
701 : uint8_t brdctl;
702 :
703 0 : if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
704 : brdctl = BRDSTB;
705 0 : if (ahc->channel == 'B')
706 0 : brdctl |= BRDCS;
707 0 : } else if ((ahc->features & AHC_ULTRA2) != 0) {
708 : brdctl = 0;
709 0 : } else {
710 : brdctl = BRDSTB|BRDCS;
711 : }
712 0 : ahc_outb(ahc, BRDCTL, brdctl);
713 0 : ahc_flush_device_writes(ahc);
714 0 : brdctl |= value;
715 0 : ahc_outb(ahc, BRDCTL, brdctl);
716 0 : ahc_flush_device_writes(ahc);
717 0 : if ((ahc->features & AHC_ULTRA2) != 0)
718 0 : brdctl |= BRDSTB_ULTRA2;
719 : else
720 0 : brdctl &= ~BRDSTB;
721 0 : ahc_outb(ahc, BRDCTL, brdctl);
722 0 : ahc_flush_device_writes(ahc);
723 0 : if ((ahc->features & AHC_ULTRA2) != 0)
724 0 : brdctl = 0;
725 : else
726 0 : brdctl &= ~BRDCS;
727 0 : ahc_outb(ahc, BRDCTL, brdctl);
728 0 : }
729 :
730 : static uint8_t
731 0 : read_brdctl(ahc)
732 : struct ahc_softc *ahc;
733 : {
734 : uint8_t brdctl;
735 : uint8_t value;
736 :
737 0 : if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
738 : brdctl = BRDRW;
739 0 : if (ahc->channel == 'B')
740 0 : brdctl |= BRDCS;
741 0 : } else if ((ahc->features & AHC_ULTRA2) != 0) {
742 : brdctl = BRDRW_ULTRA2;
743 0 : } else {
744 : brdctl = BRDRW|BRDCS;
745 : }
746 0 : ahc_outb(ahc, BRDCTL, brdctl);
747 0 : ahc_flush_device_writes(ahc);
748 0 : value = ahc_inb(ahc, BRDCTL);
749 0 : ahc_outb(ahc, BRDCTL, 0);
750 0 : return (value);
751 : }
752 :
753 : static int
754 0 : verify_seeprom_cksum(struct seeprom_config *sc)
755 : {
756 : int i;
757 : int maxaddr;
758 : uint32_t checksum;
759 : uint16_t *scarray;
760 :
761 : maxaddr = (sizeof(*sc)/2) - 1;
762 : checksum = 0;
763 0 : scarray = (uint16_t *)sc;
764 :
765 0 : for (i = 0; i < maxaddr; i++)
766 0 : checksum = checksum + scarray[i];
767 0 : if (checksum == 0
768 0 : || (checksum & 0xFFFF) != sc->checksum) {
769 0 : return (0);
770 : } else {
771 0 : return(1);
772 : }
773 0 : }
|