1 /* 2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Interface for the 93C66/56/46/26/06 serial eeprom parts. 8 * 9 * Copyright (c) 1995, 1996 Daniel M. Eischen 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 immediately at the beginning of the file, without modification, 17 * this list of conditions, and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Absolutely no warranty of function or purpose is made by the author 22 * Daniel M. Eischen. 23 * 4. Modifications may be freely made to this file if the above conditions 24 * are met. 25 * 26 * $FreeBSD: src/sys/dev/aic7xxx/93cx6.c,v 1.5 2000/01/07 23:08:17 gibbs Exp $ 27 */ 28 29 /* 30 * The instruction set of the 93C66/56/46/26/06 chips are as follows: 31 * 32 * Start OP * 33 * Function Bit Code Address** Data Description 34 * ------------------------------------------------------------------- 35 * READ 1 10 A5 - A0 Reads data stored in memory, 36 * starting at specified address 37 * EWEN 1 00 11XXXX Write enable must precede 38 * all programming modes 39 * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 40 * WRITE 1 01 A5 - A0 D15 - D0 Writes register 41 * ERAL 1 00 10XXXX Erase all registers 42 * WRAL 1 00 01XXXX D15 - D0 Writes to all registers 43 * EWDS 1 00 00XXXX Disables all programming 44 * instructions 45 * *Note: A value of X for address is a don't care condition. 46 * **Note: There are 8 address bits for the 93C56/66 chips unlike 47 * the 93C46/26/06 chips which have 6 address bits. 48 * 49 * The 93C46 has a four wire interface: clock, chip select, data in, and 50 * data out. In order to perform one of the above functions, you need 51 * to enable the chip select for a clock period (typically a minimum of 52 * 1 usec, with the clock high and low a minimum of 750 and 250 nsec 53 * respectively). While the chip select remains high, you can clock in 54 * the instructions (above) starting with the start bit, followed by the 55 * OP code, Address, and Data (if needed). For the READ instruction, the 56 * requested 16-bit register contents is read from the data out line but 57 * is preceded by an initial zero (leading 0, followed by 16-bits, MSB 58 * first). The clock cycling from low to high initiates the next data 59 * bit to be sent from the chip. 60 * 61 */ 62 63 #pragma ident "%Z%%M% %I% %E% SMI" 64 65 #include <sys/param.h> 66 #include <sys/types.h> 67 #include <sys/signal.h> 68 #include <sys/stream.h> 69 #include <sys/termio.h> 70 #include <sys/errno.h> 71 #include <sys/file.h> 72 #include <sys/cmn_err.h> 73 #include <sys/stropts.h> 74 #include <sys/strtty.h> 75 #include <sys/kbio.h> 76 #include <sys/cred.h> 77 #include <sys/stat.h> 78 #include <sys/consdev.h> 79 #include <sys/kmem.h> 80 #include <sys/modctl.h> 81 #include <sys/ddi.h> 82 #include <sys/sunddi.h> 83 #include <sys/systm.h> 84 #include "smc93cx6var.h" 85 86 /* 87 * Right now, we only have to read the SEEPROM. But we make it easier to 88 * add other 93Cx6 functions. 89 */ 90 static struct seeprom_cmd { 91 unsigned char len; 92 unsigned char bits[3]; 93 } seeprom_read = {3, {1, 1, 0}}; 94 95 #define CLOCK_PULSE(sd, rdy) { \ 96 /* \ 97 * Wait for the SEERDY to go high; about 800 ns. \ 98 */ \ 99 int cpi = 1000; \ 100 if (rdy == 0) { \ 101 DELAY(4); /* more than long enough */ \ 102 } else { \ 103 while ((SEEPROM_STATUS_INB(sd) & rdy) == 0 && \ 104 cpi-- > 0) { \ 105 cpi = cpi; /* for lint */ \ 106 } \ 107 (void) SEEPROM_INB(sd); /* Clear clock */ \ 108 } \ 109 } 110 111 /* 112 * Read the serial EEPROM and returns 1 if successful and 0 if 113 * not successful. 114 */ 115 int 116 read_seeprom(sd, buf, start_addr, count) 117 struct seeprom_descriptor *sd; 118 uint16_t *buf; 119 size_t start_addr; 120 size_t count; 121 { 122 int i = 0; 123 size_t k = 0; 124 uint16_t v; 125 uint32_t temp; 126 127 /* 128 * Read the requested registers of the seeprom. The loop 129 * will range from 0 to count-1. 130 */ 131 for (k = start_addr; k < count + start_addr; k++) { 132 /* Send chip select for one clock cycle. */ 133 temp = sd->sd_MS ^ sd->sd_CS; 134 SEEPROM_OUTB(sd, temp ^ sd->sd_CK); 135 CLOCK_PULSE(sd, sd->sd_RDY); 136 137 /* 138 * Now we're ready to send the read command followed by the 139 * address of the 16-bit register we want to read. 140 */ 141 for (i = 0; i < seeprom_read.len; i++) { 142 if (seeprom_read.bits[i] != 0) 143 temp ^= sd->sd_DO; 144 SEEPROM_OUTB(sd, temp); 145 CLOCK_PULSE(sd, sd->sd_RDY); 146 SEEPROM_OUTB(sd, temp ^ sd->sd_CK); 147 CLOCK_PULSE(sd, sd->sd_RDY); 148 if (seeprom_read.bits[i] != 0) 149 temp ^= sd->sd_DO; 150 } 151 /* Send the 6 or 8 bit address (MSB first, LSB last). */ 152 for (i = (sd->sd_chip - 1); i >= 0; i--) { 153 if ((k & (1 << i)) != 0) 154 temp ^= sd->sd_DO; 155 SEEPROM_OUTB(sd, temp); 156 CLOCK_PULSE(sd, sd->sd_RDY); 157 SEEPROM_OUTB(sd, temp ^ sd->sd_CK); 158 CLOCK_PULSE(sd, sd->sd_RDY); 159 if ((k & (1 << i)) != 0) 160 temp ^= sd->sd_DO; 161 } 162 163 /* 164 * Now read the 16 bit register. An initial 0 precedes the 165 * register contents which begins with bit 15 (MSB) and ends 166 * with bit 0 (LSB). The initial 0 will be shifted off the 167 * top of our word as we let the loop run from 0 to 16. 168 */ 169 v = 0; 170 for (i = 16; i >= 0; i--) { 171 SEEPROM_OUTB(sd, temp); 172 CLOCK_PULSE(sd, sd->sd_RDY); 173 v <<= 1; 174 if (SEEPROM_DATA_INB(sd) & sd->sd_DI) 175 v |= 1; 176 SEEPROM_OUTB(sd, temp ^ sd->sd_CK); 177 CLOCK_PULSE(sd, sd->sd_RDY); 178 } 179 180 buf[k - start_addr] = v; 181 182 /* Reset the chip select for the next command cycle. */ 183 temp = sd->sd_MS; 184 SEEPROM_OUTB(sd, temp); 185 CLOCK_PULSE(sd, sd->sd_RDY); 186 SEEPROM_OUTB(sd, temp ^ sd->sd_CK); 187 CLOCK_PULSE(sd, sd->sd_RDY); 188 SEEPROM_OUTB(sd, temp); 189 CLOCK_PULSE(sd, sd->sd_RDY); 190 } 191 #ifdef AHC_DUMP_EEPROM 192 cmn_err(CE_NOTE, "\nSerial EEPROM:\n\t"); 193 for (k = 0; k < count; k = k + 1) { 194 cmn_err(CE_NOTE, " 0x%x", buf[k]); 195 } 196 #endif 197 return (1); 198 } 199