diff options
Diffstat (limited to 'drivers/scsi/aic7xxx/aic7xxx_93cx6.c')
-rw-r--r-- | drivers/scsi/aic7xxx/aic7xxx_93cx6.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c new file mode 100644 index 000000000000..468d612a44f6 --- /dev/null +++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c | |||
@@ -0,0 +1,306 @@ | |||
1 | /* | ||
2 | * Interface for the 93C66/56/46/26/06 serial eeprom parts. | ||
3 | * | ||
4 | * Copyright (c) 1995, 1996 Daniel M. Eischen | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions, and the following disclaimer, | ||
12 | * without modification. | ||
13 | * 2. The name of the author may not be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * Alternatively, this software may be distributed under the terms of the | ||
17 | * GNU General Public License ("GPL"). | ||
18 | * | ||
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
29 | * SUCH DAMAGE. | ||
30 | * | ||
31 | * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#17 $ | ||
32 | * | ||
33 | * $FreeBSD$ | ||
34 | */ | ||
35 | |||
36 | /* | ||
37 | * The instruction set of the 93C66/56/46/26/06 chips are as follows: | ||
38 | * | ||
39 | * Start OP * | ||
40 | * Function Bit Code Address** Data Description | ||
41 | * ------------------------------------------------------------------- | ||
42 | * READ 1 10 A5 - A0 Reads data stored in memory, | ||
43 | * starting at specified address | ||
44 | * EWEN 1 00 11XXXX Write enable must precede | ||
45 | * all programming modes | ||
46 | * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 | ||
47 | * WRITE 1 01 A5 - A0 D15 - D0 Writes register | ||
48 | * ERAL 1 00 10XXXX Erase all registers | ||
49 | * WRAL 1 00 01XXXX D15 - D0 Writes to all registers | ||
50 | * EWDS 1 00 00XXXX Disables all programming | ||
51 | * instructions | ||
52 | * *Note: A value of X for address is a don't care condition. | ||
53 | * **Note: There are 8 address bits for the 93C56/66 chips unlike | ||
54 | * the 93C46/26/06 chips which have 6 address bits. | ||
55 | * | ||
56 | * The 93C46 has a four wire interface: clock, chip select, data in, and | ||
57 | * data out. In order to perform one of the above functions, you need | ||
58 | * to enable the chip select for a clock period (typically a minimum of | ||
59 | * 1 usec, with the clock high and low a minimum of 750 and 250 nsec | ||
60 | * respectively). While the chip select remains high, you can clock in | ||
61 | * the instructions (above) starting with the start bit, followed by the | ||
62 | * OP code, Address, and Data (if needed). For the READ instruction, the | ||
63 | * requested 16-bit register contents is read from the data out line but | ||
64 | * is preceded by an initial zero (leading 0, followed by 16-bits, MSB | ||
65 | * first). The clock cycling from low to high initiates the next data | ||
66 | * bit to be sent from the chip. | ||
67 | * | ||
68 | */ | ||
69 | |||
70 | #ifdef __linux__ | ||
71 | #include "aic7xxx_osm.h" | ||
72 | #include "aic7xxx_inline.h" | ||
73 | #include "aic7xxx_93cx6.h" | ||
74 | #else | ||
75 | #include <dev/aic7xxx/aic7xxx_osm.h> | ||
76 | #include <dev/aic7xxx/aic7xxx_inline.h> | ||
77 | #include <dev/aic7xxx/aic7xxx_93cx6.h> | ||
78 | #endif | ||
79 | |||
80 | /* | ||
81 | * Right now, we only have to read the SEEPROM. But we make it easier to | ||
82 | * add other 93Cx6 functions. | ||
83 | */ | ||
84 | static struct seeprom_cmd { | ||
85 | uint8_t len; | ||
86 | uint8_t bits[9]; | ||
87 | } seeprom_read = {3, {1, 1, 0}}; | ||
88 | |||
89 | static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; | ||
90 | static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; | ||
91 | static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}}; | ||
92 | |||
93 | /* | ||
94 | * Wait for the SEERDY to go high; about 800 ns. | ||
95 | */ | ||
96 | #define CLOCK_PULSE(sd, rdy) \ | ||
97 | while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) { \ | ||
98 | ; /* Do nothing */ \ | ||
99 | } \ | ||
100 | (void)SEEPROM_INB(sd); /* Clear clock */ | ||
101 | |||
102 | /* | ||
103 | * Send a START condition and the given command | ||
104 | */ | ||
105 | static void | ||
106 | send_seeprom_cmd(struct seeprom_descriptor *sd, struct seeprom_cmd *cmd) | ||
107 | { | ||
108 | uint8_t temp; | ||
109 | int i = 0; | ||
110 | |||
111 | /* Send chip select for one clock cycle. */ | ||
112 | temp = sd->sd_MS ^ sd->sd_CS; | ||
113 | SEEPROM_OUTB(sd, temp ^ sd->sd_CK); | ||
114 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
115 | |||
116 | for (i = 0; i < cmd->len; i++) { | ||
117 | if (cmd->bits[i] != 0) | ||
118 | temp ^= sd->sd_DO; | ||
119 | SEEPROM_OUTB(sd, temp); | ||
120 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
121 | SEEPROM_OUTB(sd, temp ^ sd->sd_CK); | ||
122 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
123 | if (cmd->bits[i] != 0) | ||
124 | temp ^= sd->sd_DO; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * Clear CS put the chip in the reset state, where it can wait for new commands. | ||
130 | */ | ||
131 | static void | ||
132 | reset_seeprom(struct seeprom_descriptor *sd) | ||
133 | { | ||
134 | uint8_t temp; | ||
135 | |||
136 | temp = sd->sd_MS; | ||
137 | SEEPROM_OUTB(sd, temp); | ||
138 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
139 | SEEPROM_OUTB(sd, temp ^ sd->sd_CK); | ||
140 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
141 | SEEPROM_OUTB(sd, temp); | ||
142 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Read the serial EEPROM and returns 1 if successful and 0 if | ||
147 | * not successful. | ||
148 | */ | ||
149 | int | ||
150 | ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, | ||
151 | u_int start_addr, u_int count) | ||
152 | { | ||
153 | int i = 0; | ||
154 | u_int k = 0; | ||
155 | uint16_t v; | ||
156 | uint8_t temp; | ||
157 | |||
158 | /* | ||
159 | * Read the requested registers of the seeprom. The loop | ||
160 | * will range from 0 to count-1. | ||
161 | */ | ||
162 | for (k = start_addr; k < count + start_addr; k++) { | ||
163 | /* | ||
164 | * Now we're ready to send the read command followed by the | ||
165 | * address of the 16-bit register we want to read. | ||
166 | */ | ||
167 | send_seeprom_cmd(sd, &seeprom_read); | ||
168 | |||
169 | /* Send the 6 or 8 bit address (MSB first, LSB last). */ | ||
170 | temp = sd->sd_MS ^ sd->sd_CS; | ||
171 | for (i = (sd->sd_chip - 1); i >= 0; i--) { | ||
172 | if ((k & (1 << i)) != 0) | ||
173 | temp ^= sd->sd_DO; | ||
174 | SEEPROM_OUTB(sd, temp); | ||
175 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
176 | SEEPROM_OUTB(sd, temp ^ sd->sd_CK); | ||
177 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
178 | if ((k & (1 << i)) != 0) | ||
179 | temp ^= sd->sd_DO; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Now read the 16 bit register. An initial 0 precedes the | ||
184 | * register contents which begins with bit 15 (MSB) and ends | ||
185 | * with bit 0 (LSB). The initial 0 will be shifted off the | ||
186 | * top of our word as we let the loop run from 0 to 16. | ||
187 | */ | ||
188 | v = 0; | ||
189 | for (i = 16; i >= 0; i--) { | ||
190 | SEEPROM_OUTB(sd, temp); | ||
191 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
192 | v <<= 1; | ||
193 | if (SEEPROM_DATA_INB(sd) & sd->sd_DI) | ||
194 | v |= 1; | ||
195 | SEEPROM_OUTB(sd, temp ^ sd->sd_CK); | ||
196 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
197 | } | ||
198 | |||
199 | buf[k - start_addr] = v; | ||
200 | |||
201 | /* Reset the chip select for the next command cycle. */ | ||
202 | reset_seeprom(sd); | ||
203 | } | ||
204 | #ifdef AHC_DUMP_EEPROM | ||
205 | printf("\nSerial EEPROM:\n\t"); | ||
206 | for (k = 0; k < count; k = k + 1) { | ||
207 | if (((k % 8) == 0) && (k != 0)) { | ||
208 | printf ("\n\t"); | ||
209 | } | ||
210 | printf (" 0x%x", buf[k]); | ||
211 | } | ||
212 | printf ("\n"); | ||
213 | #endif | ||
214 | return (1); | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Write the serial EEPROM and return 1 if successful and 0 if | ||
219 | * not successful. | ||
220 | */ | ||
221 | int | ||
222 | ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, | ||
223 | u_int start_addr, u_int count) | ||
224 | { | ||
225 | uint16_t v; | ||
226 | uint8_t temp; | ||
227 | int i, k; | ||
228 | |||
229 | /* Place the chip into write-enable mode */ | ||
230 | send_seeprom_cmd(sd, &seeprom_ewen); | ||
231 | reset_seeprom(sd); | ||
232 | |||
233 | /* Write all requested data out to the seeprom. */ | ||
234 | temp = sd->sd_MS ^ sd->sd_CS; | ||
235 | for (k = start_addr; k < count + start_addr; k++) { | ||
236 | /* Send the write command */ | ||
237 | send_seeprom_cmd(sd, &seeprom_write); | ||
238 | |||
239 | /* Send the 6 or 8 bit address (MSB first). */ | ||
240 | for (i = (sd->sd_chip - 1); i >= 0; i--) { | ||
241 | if ((k & (1 << i)) != 0) | ||
242 | temp ^= sd->sd_DO; | ||
243 | SEEPROM_OUTB(sd, temp); | ||
244 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
245 | SEEPROM_OUTB(sd, temp ^ sd->sd_CK); | ||
246 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
247 | if ((k & (1 << i)) != 0) | ||
248 | temp ^= sd->sd_DO; | ||
249 | } | ||
250 | |||
251 | /* Write the 16 bit value, MSB first */ | ||
252 | v = buf[k - start_addr]; | ||
253 | for (i = 15; i >= 0; i--) { | ||
254 | if ((v & (1 << i)) != 0) | ||
255 | temp ^= sd->sd_DO; | ||
256 | SEEPROM_OUTB(sd, temp); | ||
257 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
258 | SEEPROM_OUTB(sd, temp ^ sd->sd_CK); | ||
259 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
260 | if ((v & (1 << i)) != 0) | ||
261 | temp ^= sd->sd_DO; | ||
262 | } | ||
263 | |||
264 | /* Wait for the chip to complete the write */ | ||
265 | temp = sd->sd_MS; | ||
266 | SEEPROM_OUTB(sd, temp); | ||
267 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
268 | temp = sd->sd_MS ^ sd->sd_CS; | ||
269 | do { | ||
270 | SEEPROM_OUTB(sd, temp); | ||
271 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
272 | SEEPROM_OUTB(sd, temp ^ sd->sd_CK); | ||
273 | CLOCK_PULSE(sd, sd->sd_RDY); | ||
274 | } while ((SEEPROM_DATA_INB(sd) & sd->sd_DI) == 0); | ||
275 | |||
276 | reset_seeprom(sd); | ||
277 | } | ||
278 | |||
279 | /* Put the chip back into write-protect mode */ | ||
280 | send_seeprom_cmd(sd, &seeprom_ewds); | ||
281 | reset_seeprom(sd); | ||
282 | |||
283 | return (1); | ||
284 | } | ||
285 | |||
286 | int | ||
287 | ahc_verify_cksum(struct seeprom_config *sc) | ||
288 | { | ||
289 | int i; | ||
290 | int maxaddr; | ||
291 | uint32_t checksum; | ||
292 | uint16_t *scarray; | ||
293 | |||
294 | maxaddr = (sizeof(*sc)/2) - 1; | ||
295 | checksum = 0; | ||
296 | scarray = (uint16_t *)sc; | ||
297 | |||
298 | for (i = 0; i < maxaddr; i++) | ||
299 | checksum = checksum + scarray[i]; | ||
300 | if (checksum == 0 | ||
301 | || (checksum & 0xFFFF) != sc->checksum) { | ||
302 | return (0); | ||
303 | } else { | ||
304 | return(1); | ||
305 | } | ||
306 | } | ||