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
79static void configure_termination(struct ahc_softc *,
80				  struct seeprom_descriptor *, u_int, u_int *);
81static int verify_seeprom_cksum(struct seeprom_config *sc);
82
83static void ahc_new_term_detect(struct ahc_softc *, int *, int *, int *,
84				   int *, int *);
85static void aic787X_cable_detect(struct ahc_softc *, int *, int *, int *,
86				 int *);
87static void aic785X_cable_detect(struct ahc_softc *, int *, int *, int *);
88static void write_brdctl(struct ahc_softc *, u_int8_t);
89static u_int8_t read_brdctl(struct ahc_softc *);
90static 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 */
96void
97ahc_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
241static void
242ahc_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
357static void
358configure_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
583static void
584ahc_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
605static void
606aic787X_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
646static void
647aic785X_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
666int
667ahc_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
694void
695ahc_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
701static void
702write_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
733static uint8_t
734read_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
755static int
756verify_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}
776