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