aic7xxx_93cx6.c revision 47507
175115Sfenner/* 275115Sfenner * Interface for the 93C66/56/46/26/06 serial eeprom parts. 375115Sfenner * 475115Sfenner * Copyright (c) 1995, 1996 Daniel M. Eischen 575115Sfenner * All rights reserved. 675115Sfenner * 775115Sfenner * Redistribution and use in source and binary forms, with or without 875115Sfenner * modification, are permitted provided that the following conditions 975115Sfenner * are met: 1075115Sfenner * 1. Redistributions of source code must retain the above copyright 1175115Sfenner * notice immediately at the beginning of the file, without modification, 1275115Sfenner * this list of conditions, and the following disclaimer. 1375115Sfenner * 2. Redistributions in binary form must reproduce the above copyright 1475115Sfenner * notice, this list of conditions and the following disclaimer in the 1575115Sfenner * documentation and/or other materials provided with the distribution. 1675115Sfenner * 3. Absolutely no warranty of function or purpose is made by the author 1775115Sfenner * Daniel M. Eischen. 1875115Sfenner * 4. Modifications may be freely made to this file if the above conditions 1975115Sfenner * are met. 2075115Sfenner * 2175115Sfenner * $Id: 93cx6.c,v 1.2 1999/04/07 23:02:45 gibbs Exp $ 2275115Sfenner */ 23127668Sbms 24190207Srpaulo/* 2575115Sfenner * The instruction set of the 93C66/56/46/26/06 chips are as follows: 2675115Sfenner * 2775115Sfenner * Start OP * 2875115Sfenner * Function Bit Code Address** Data Description 2975115Sfenner * ------------------------------------------------------------------- 3075115Sfenner * READ 1 10 A5 - A0 Reads data stored in memory, 31127668Sbms * starting at specified address 3275115Sfenner * EWEN 1 00 11XXXX Write enable must preceed 3375115Sfenner * all programming modes 3475115Sfenner * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 3575115Sfenner * WRITE 1 01 A5 - A0 D15 - D0 Writes register 3675115Sfenner * ERAL 1 00 10XXXX Erase all registers 3775115Sfenner * WRAL 1 00 01XXXX D15 - D0 Writes to all registers 3875115Sfenner * EWDS 1 00 00XXXX Disables all programming 3975115Sfenner * instructions 4075115Sfenner * *Note: A value of X for address is a don't care condition. 4175115Sfenner * **Note: There are 8 address bits for the 93C56/66 chips unlike 4275115Sfenner * the 93C46/26/06 chips which have 6 address bits. 4375115Sfenner * 4475115Sfenner * The 93C46 has a four wire interface: clock, chip select, data in, and 4575115Sfenner * data out. In order to perform one of the above functions, you need 4675115Sfenner * to enable the chip select for a clock period (typically a minimum of 4775115Sfenner * 1 usec, with the clock high and low a minimum of 750 and 250 nsec 4875115Sfenner * respectively). While the chip select remains high, you can clock in 4975115Sfenner * the instructions (above) starting with the start bit, followed by the 50127668Sbms * OP code, Address, and Data (if needed). For the READ instruction, the 51127668Sbms * requested 16-bit register contents is read from the data out line but 52127668Sbms * is preceded by an initial zero (leading 0, followed by 16-bits, MSB 53127668Sbms * first). The clock cycling from low to high initiates the next data 5475115Sfenner * bit to be sent from the chip. 5575115Sfenner * 5675115Sfenner */ 5775115Sfenner 5875115Sfenner#include "opt_aic7xxx.h" 5975115Sfenner 6075115Sfenner#include <sys/param.h> 6175115Sfenner#include <sys/systm.h> 6275115Sfenner#include <machine/bus_memio.h> 6375115Sfenner#include <machine/bus_pio.h> 64127668Sbms#include <machine/bus.h> 65127668Sbms#include <dev/aic7xxx/93cx6.h> 66127668Sbms 67127668Sbms/* 68127668Sbms * Right now, we only have to read the SEEPROM. But we make it easier to 69127668Sbms * add other 93Cx6 functions. 70127668Sbms */ 71127668Sbmsstatic struct seeprom_cmd { 72127668Sbms unsigned char len; 73127668Sbms unsigned char bits[3]; 74127668Sbms} seeprom_read = {3, {1, 1, 0}}; 7575115Sfenner 7675115Sfenner/* 7775115Sfenner * Wait for the SEERDY to go high; about 800 ns. 7875115Sfenner */ 7975115Sfenner#define CLOCK_PULSE(sd, rdy) \ 8075115Sfenner while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) { \ 8175115Sfenner ; /* Do nothing */ \ 8275115Sfenner } \ 8375115Sfenner (void)SEEPROM_INB(sd); /* Clear clock */ 8475115Sfenner 8575115Sfenner/* 8675115Sfenner * Read the serial EEPROM and returns 1 if successful and 0 if 8775115Sfenner * not successful. 8875115Sfenner */ 8975115Sfennerint 9075115Sfennerread_seeprom(sd, buf, start_addr, count) 9175115Sfenner struct seeprom_descriptor *sd; 9275115Sfenner u_int16_t *buf; 9375115Sfenner bus_size_t start_addr; 9475115Sfenner bus_size_t count; 9575115Sfenner{ 9675115Sfenner int i = 0; 9775115Sfenner u_int k = 0; 9875115Sfenner u_int16_t v; 9975115Sfenner u_int8_t temp; 10075115Sfenner 10175115Sfenner /* 10275115Sfenner * Read the requested registers of the seeprom. The loop 10375115Sfenner * will range from 0 to count-1. 10475115Sfenner */ 10575115Sfenner for (k = start_addr; k < count + start_addr; k++) { 10675115Sfenner /* Send chip select for one clock cycle. */ 10775115Sfenner temp = sd->sd_MS ^ sd->sd_CS; 10875115Sfenner SEEPROM_OUTB(sd, temp ^ sd->sd_CK); 109127668Sbms CLOCK_PULSE(sd, sd->sd_RDY); 11075115Sfenner 11175115Sfenner /* 11298524Sfenner * Now we're ready to send the read command followed by the 11375115Sfenner * address of the 16-bit register we want to read. 114127668Sbms */ 115127668Sbms for (i = 0; i < seeprom_read.len; i++) { 116127668Sbms if (seeprom_read.bits[i] != 0) 117127668Sbms temp ^= sd->sd_DO; 118127668Sbms SEEPROM_OUTB(sd, temp); 119127668Sbms CLOCK_PULSE(sd, sd->sd_RDY); 120127668Sbms SEEPROM_OUTB(sd, temp ^ sd->sd_CK); 12175115Sfenner CLOCK_PULSE(sd, sd->sd_RDY); 12275115Sfenner if (seeprom_read.bits[i] != 0) 123127668Sbms temp ^= sd->sd_DO; 124127668Sbms } 125127668Sbms /* Send the 6 or 8 bit address (MSB first, LSB last). */ 126127668Sbms for (i = (sd->sd_chip - 1); i >= 0; i--) { 127127668Sbms if ((k & (1 << i)) != 0) 128127668Sbms temp ^= sd->sd_DO; 12975115Sfenner SEEPROM_OUTB(sd, temp); 13075115Sfenner CLOCK_PULSE(sd, sd->sd_RDY); 131127668Sbms SEEPROM_OUTB(sd, temp ^ sd->sd_CK); 13275115Sfenner CLOCK_PULSE(sd, sd->sd_RDY); 13375115Sfenner if ((k & (1 << i)) != 0) 13498524Sfenner temp ^= sd->sd_DO; 13575115Sfenner } 136127668Sbms 137127668Sbms /* 138127668Sbms * Now read the 16 bit register. An initial 0 precedes the 139127668Sbms * register contents which begins with bit 15 (MSB) and ends 140127668Sbms * with bit 0 (LSB). The initial 0 will be shifted off the 14175115Sfenner * top of our word as we let the loop run from 0 to 16. 142127668Sbms */ 14375115Sfenner v = 0; 14475115Sfenner for (i = 16; i >= 0; i--) { 145127668Sbms SEEPROM_OUTB(sd, temp); 146127668Sbms CLOCK_PULSE(sd, sd->sd_RDY); 147127668Sbms v <<= 1; 148127668Sbms if (SEEPROM_DATA_INB(sd) & sd->sd_DI) 149127668Sbms v |= 1; 150127668Sbms SEEPROM_OUTB(sd, temp ^ sd->sd_CK); 15175115Sfenner CLOCK_PULSE(sd, sd->sd_RDY); 15275115Sfenner } 153127668Sbms 15498524Sfenner buf[k - start_addr] = v; 15575115Sfenner 15698524Sfenner /* Reset the chip select for the next command cycle. */ 15798524Sfenner temp = sd->sd_MS; 15875115Sfenner SEEPROM_OUTB(sd, temp); 15975115Sfenner CLOCK_PULSE(sd, sd->sd_RDY); 16075115Sfenner SEEPROM_OUTB(sd, temp ^ sd->sd_CK); 161127668Sbms CLOCK_PULSE(sd, sd->sd_RDY); 162127668Sbms SEEPROM_OUTB(sd, temp); 16375115Sfenner CLOCK_PULSE(sd, sd->sd_RDY); 16475115Sfenner } 16575115Sfenner#ifdef AHC_DUMP_EEPROM 166127668Sbms printf("\nSerial EEPROM:"); 16775115Sfenner for (k = 0; k < count; k = k + 1) { 16875115Sfenner if (((k % 8) == 0) && (k != 0)) { 169127668Sbms printf ("\n "); 17075115Sfenner } 17175115Sfenner printf (" 0x%x", buf[k]); 17275115Sfenner } 17375115Sfenner printf ("\n"); 17475115Sfenner#endif 17575115Sfenner return (1); 17675115Sfenner} 17775115Sfenner