aic7xxx_93cx6.c revision 55581
139220Sgibbs/*
239220Sgibbs * Interface for the 93C66/56/46/26/06 serial eeprom parts.
339220Sgibbs *
439220Sgibbs * Copyright (c) 1995, 1996 Daniel M. Eischen
539220Sgibbs * All rights reserved.
639220Sgibbs *
739220Sgibbs * Redistribution and use in source and binary forms, with or without
839220Sgibbs * modification, are permitted provided that the following conditions
939220Sgibbs * are met:
1039220Sgibbs * 1. Redistributions of source code must retain the above copyright
1139220Sgibbs *    notice immediately at the beginning of the file, without modification,
1239220Sgibbs *    this list of conditions, and the following disclaimer.
1339220Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1439220Sgibbs *    notice, this list of conditions and the following disclaimer in the
1539220Sgibbs *    documentation and/or other materials provided with the distribution.
1639220Sgibbs * 3. Absolutely no warranty of function or purpose is made by the author
1739220Sgibbs *    Daniel M. Eischen.
1839220Sgibbs * 4. Modifications may be freely made to this file if the above conditions
1939220Sgibbs *    are met.
2039220Sgibbs *
2150477Speter * $FreeBSD: head/sys/dev/aic7xxx/aic7xxx_93cx6.c 55581 2000-01-07 23:08:20Z gibbs $
2239220Sgibbs */
2339220Sgibbs
2439220Sgibbs/*
2539220Sgibbs *   The instruction set of the 93C66/56/46/26/06 chips are as follows:
2639220Sgibbs *
2739220Sgibbs *               Start  OP	    *
2839220Sgibbs *     Function   Bit  Code  Address**  Data     Description
2939220Sgibbs *     -------------------------------------------------------------------
3039220Sgibbs *     READ        1    10   A5 - A0             Reads data stored in memory,
3139220Sgibbs *                                               starting at specified address
3239220Sgibbs *     EWEN        1    00   11XXXX              Write enable must preceed
3339220Sgibbs *                                               all programming modes
3439220Sgibbs *     ERASE       1    11   A5 - A0             Erase register A5A4A3A2A1A0
3539220Sgibbs *     WRITE       1    01   A5 - A0   D15 - D0  Writes register
3639220Sgibbs *     ERAL        1    00   10XXXX              Erase all registers
3739220Sgibbs *     WRAL        1    00   01XXXX    D15 - D0  Writes to all registers
3839220Sgibbs *     EWDS        1    00   00XXXX              Disables all programming
3939220Sgibbs *                                               instructions
4039220Sgibbs *     *Note: A value of X for address is a don't care condition.
4139220Sgibbs *    **Note: There are 8 address bits for the 93C56/66 chips unlike
4239220Sgibbs *	      the 93C46/26/06 chips which have 6 address bits.
4339220Sgibbs *
4439220Sgibbs *   The 93C46 has a four wire interface: clock, chip select, data in, and
4539220Sgibbs *   data out.  In order to perform one of the above functions, you need
4639220Sgibbs *   to enable the chip select for a clock period (typically a minimum of
4739220Sgibbs *   1 usec, with the clock high and low a minimum of 750 and 250 nsec
4839220Sgibbs *   respectively).  While the chip select remains high, you can clock in
4939220Sgibbs *   the instructions (above) starting with the start bit, followed by the
5039220Sgibbs *   OP code, Address, and Data (if needed).  For the READ instruction, the
5139220Sgibbs *   requested 16-bit register contents is read from the data out line but
5239220Sgibbs *   is preceded by an initial zero (leading 0, followed by 16-bits, MSB
5339220Sgibbs *   first).  The clock cycling from low to high initiates the next data
5439220Sgibbs *   bit to be sent from the chip.
5539220Sgibbs *
5639220Sgibbs */
5739220Sgibbs
5847507Sgibbs#include "opt_aic7xxx.h"
5947507Sgibbs
6039220Sgibbs#include <sys/param.h>
6139220Sgibbs#include <sys/systm.h>
6239220Sgibbs#include <machine/bus_memio.h>
6339220Sgibbs#include <machine/bus_pio.h>
6439220Sgibbs#include <machine/bus.h>
6539220Sgibbs#include <dev/aic7xxx/93cx6.h>
6639220Sgibbs
6739220Sgibbs/*
6839220Sgibbs * Right now, we only have to read the SEEPROM.  But we make it easier to
6939220Sgibbs * add other 93Cx6 functions.
7039220Sgibbs */
7139220Sgibbsstatic struct seeprom_cmd {
7239220Sgibbs  	unsigned char len;
7339220Sgibbs 	unsigned char bits[3];
7439220Sgibbs} seeprom_read = {3, {1, 1, 0}};
7539220Sgibbs
7639220Sgibbs/*
7739220Sgibbs * Wait for the SEERDY to go high; about 800 ns.
7839220Sgibbs */
7939220Sgibbs#define CLOCK_PULSE(sd, rdy)				\
8039220Sgibbs	while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) {	\
8139220Sgibbs		;  /* Do nothing */			\
8239220Sgibbs	}						\
8339220Sgibbs	(void)SEEPROM_INB(sd);	/* Clear clock */
8439220Sgibbs
8539220Sgibbs/*
8639220Sgibbs * Read the serial EEPROM and returns 1 if successful and 0 if
8739220Sgibbs * not successful.
8839220Sgibbs */
8939220Sgibbsint
9039220Sgibbsread_seeprom(sd, buf, start_addr, count)
9139220Sgibbs	struct seeprom_descriptor *sd;
9239220Sgibbs	u_int16_t *buf;
9339220Sgibbs	bus_size_t start_addr;
9439220Sgibbs	bus_size_t count;
9539220Sgibbs{
9639220Sgibbs	int i = 0;
9739220Sgibbs	u_int k = 0;
9839220Sgibbs	u_int16_t v;
9939220Sgibbs	u_int8_t temp;
10039220Sgibbs
10139220Sgibbs	/*
10239220Sgibbs	 * Read the requested registers of the seeprom.  The loop
10339220Sgibbs	 * will range from 0 to count-1.
10439220Sgibbs	 */
10539220Sgibbs	for (k = start_addr; k < count + start_addr; k++) {
10639220Sgibbs		/* Send chip select for one clock cycle. */
10739220Sgibbs		temp = sd->sd_MS ^ sd->sd_CS;
10839220Sgibbs		SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
10939220Sgibbs		CLOCK_PULSE(sd, sd->sd_RDY);
11039220Sgibbs
11139220Sgibbs		/*
11239220Sgibbs		 * Now we're ready to send the read command followed by the
11339220Sgibbs		 * address of the 16-bit register we want to read.
11439220Sgibbs		 */
11539220Sgibbs		for (i = 0; i < seeprom_read.len; i++) {
11639220Sgibbs			if (seeprom_read.bits[i] != 0)
11739220Sgibbs				temp ^= sd->sd_DO;
11839220Sgibbs			SEEPROM_OUTB(sd, temp);
11939220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
12039220Sgibbs			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
12139220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
12239220Sgibbs			if (seeprom_read.bits[i] != 0)
12339220Sgibbs				temp ^= sd->sd_DO;
12439220Sgibbs		}
12539220Sgibbs		/* Send the 6 or 8 bit address (MSB first, LSB last). */
12639220Sgibbs		for (i = (sd->sd_chip - 1); i >= 0; i--) {
12739220Sgibbs			if ((k & (1 << i)) != 0)
12839220Sgibbs				temp ^= sd->sd_DO;
12939220Sgibbs			SEEPROM_OUTB(sd, temp);
13039220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
13139220Sgibbs			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
13239220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
13339220Sgibbs			if ((k & (1 << i)) != 0)
13439220Sgibbs				temp ^= sd->sd_DO;
13539220Sgibbs		}
13639220Sgibbs
13739220Sgibbs		/*
13839220Sgibbs		 * Now read the 16 bit register.  An initial 0 precedes the
13939220Sgibbs		 * register contents which begins with bit 15 (MSB) and ends
14039220Sgibbs		 * with bit 0 (LSB).  The initial 0 will be shifted off the
14139220Sgibbs		 * top of our word as we let the loop run from 0 to 16.
14239220Sgibbs		 */
14339220Sgibbs		v = 0;
14439220Sgibbs		for (i = 16; i >= 0; i--) {
14539220Sgibbs			SEEPROM_OUTB(sd, temp);
14639220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
14739220Sgibbs			v <<= 1;
14839220Sgibbs			if (SEEPROM_DATA_INB(sd) & sd->sd_DI)
14939220Sgibbs				v |= 1;
15039220Sgibbs			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
15139220Sgibbs			CLOCK_PULSE(sd, sd->sd_RDY);
15239220Sgibbs		}
15339220Sgibbs
15439220Sgibbs		buf[k - start_addr] = v;
15539220Sgibbs
15639220Sgibbs		/* Reset the chip select for the next command cycle. */
15739220Sgibbs		temp = sd->sd_MS;
15839220Sgibbs		SEEPROM_OUTB(sd, temp);
15939220Sgibbs		CLOCK_PULSE(sd, sd->sd_RDY);
16039220Sgibbs		SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
16139220Sgibbs		CLOCK_PULSE(sd, sd->sd_RDY);
16239220Sgibbs		SEEPROM_OUTB(sd, temp);
16339220Sgibbs		CLOCK_PULSE(sd, sd->sd_RDY);
16439220Sgibbs	}
16547507Sgibbs#ifdef AHC_DUMP_EEPROM
16655581Sgibbs	printf("\nSerial EEPROM:\n\t");
16739220Sgibbs	for (k = 0; k < count; k = k + 1) {
16839220Sgibbs		if (((k % 8) == 0) && (k != 0)) {
16955581Sgibbs			printf ("\n\t");
17039220Sgibbs		}
17139220Sgibbs		printf (" 0x%x", buf[k]);
17239220Sgibbs	}
17339220Sgibbs	printf ("\n");
17439220Sgibbs#endif
17539220Sgibbs	return (1);
17639220Sgibbs}
177