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