1 /* Copyright(c) 2000, Compaq Computer Corporation
2  * Fibre Channel Host Bus Adapter
3  * 64-bit, 66MHz PCI
4  * Originally developed and tested on:
5  * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
6  *          SP# P225CXCBFIEL6T, Rev XC
7  *          SP# 161290-001, Rev XD
8  * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the
12  * Free Software Foundation; either version 2, or (at your option) any
13  * later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  * Written by Don Zimmerman
20 */
21 // These functions control the NVRAM I2C hardware on
22 // non-intelligent Fibre Host Adapters.
23 // The primary purpose is to read the HBA's NVRAM to get adapter's
24 // manufactured WWN to copy into Tachyon chip registers
25 // Orignal source author unknown
26 
27 #include <linux/types.h>
28 #include <linux/string.h>
29 #include <linux/pci.h>
30 #include <linux/delay.h>
31 #include <linux/sched.h>
32 #include <asm/io.h>		// struct pt_regs for IRQ handler & Port I/O
33 
34 #include "cpqfcTSchip.h"
35 
36 static void tl_i2c_tx_byte(void *GPIOout, u8 data);
37 
38 /*
39  * Tachlite GPIO2, GPIO3 (I2C) DEFINES
40  * The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
41  * GPIO2 drives SDA, and GPIO3 drives SCL
42  *
43  * Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
44  * and clear writes 1. The input lines (read in TL status) is NOT inverted
45  * This really helps confuse the code and debugging.
46  */
47 
48 #define SET_DATA_HI		0x0
49 #define SET_DATA_LO		0x8
50 #define SET_CLOCK_HI		0x0
51 #define SET_CLOCK_LO		0x4
52 
53 #define SENSE_DATA_HI		0x8
54 #define SENSE_DATA_LO		0x0
55 #define SENSE_CLOCK_HI		0x4
56 #define SENSE_CLOCK_LO		0x0
57 
58 #define SLAVE_READ_ADDRESS	0xA1
59 #define SLAVE_WRITE_ADDRESS	0xA0
60 
61 
62 static void tl_i2c_clock_pulse(u8, void *GPIOout);
63 static u8 tl_read_i2c_data(void *);
64 
65 
66 //-----------------------------------------------------------------------------
67 //
68 //      Name:   tl_i2c_rx_ack
69 //
70 //      This routine receives an acknowledge over the I2C bus.
71 //
72 //-----------------------------------------------------------------------------
tl_i2c_rx_ack(void * GPIOin,void * GPIOout)73 static unsigned short tl_i2c_rx_ack(void *GPIOin, void *GPIOout)
74 {
75 	unsigned long value;
76 
77 	// do clock pulse, let data line float high
78 	tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
79 
80 	// slave must drive data low for acknowledge
81 	value = tl_read_i2c_data(GPIOin);
82 	if (value & SENSE_DATA_HI)
83 		return 0;
84 
85 	return 1;
86 }
87 
88 //-----------------------------------------------------------------------------
89 //
90 //      Name:   tl_read_i2c_reg
91 //
92 //      This routine reads the I2C control register using the global
93 //      IO address stored in gpioreg.
94 //
95 //-----------------------------------------------------------------------------
tl_read_i2c_data(void * gpioreg)96 static u8 tl_read_i2c_data(void *gpioreg)
97 {
98 	return ((u8) (readl(gpioreg) & 0x08L));	// GPIO3
99 }
100 
101 //-----------------------------------------------------------------------------
102 //
103 //      Name:   tl_write_i2c_reg
104 //
105 //      This routine writes the I2C control register using the global
106 //      IO address stored in gpioreg.
107 //      In Tachlite, we don't want to modify other bits in TL Control reg.
108 //
109 //-----------------------------------------------------------------------------
tl_write_i2c_reg(void * gpioregOUT,u8 value)110 static void tl_write_i2c_reg(void *gpioregOUT, u8 value)
111 {
112 	u32 temp;
113 
114 	// First read the register and clear out the old bits
115 	temp = readl(gpioregOUT) & 0xfffffff3L;
116 
117 	// Now or in the new data and send it back out
118 	writel(temp | value, gpioregOUT);
119 
120 	/* PCI posting ???? */
121 }
122 
123 //-----------------------------------------------------------------------------
124 //
125 //      Name:   tl_i2c_tx_start
126 //
127 //      This routine transmits a start condition over the I2C bus.
128 //      1. Set SCL (clock, GPIO2) HIGH, set SDA (data, GPIO3) HIGH,
129 //      wait 5us to stabilize.
130 //      2. With SCL still HIGH, drive SDA low.  The low transition marks
131 //         the start condition to NM24Cxx (the chip)
132 //      NOTE! In TL control reg., output 1 means chip sees LOW
133 //
134 //-----------------------------------------------------------------------------
tl_i2c_tx_start(void * GPIOin,void * GPIOout)135 static unsigned short tl_i2c_tx_start(void *GPIOin, void *GPIOout)
136 {
137 	unsigned short i;
138 	u32 value;
139 
140 	if (!(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)) {
141 		// start with clock high, let data float high
142 		tl_write_i2c_reg(GPIOout, SET_DATA_HI | SET_CLOCK_HI);
143 
144 		// keep sending clock pulses if slave is driving data line
145 		for (i = 0; i < 10; i++) {
146 			tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
147 
148 			if (tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)
149 				break;
150 		}
151 
152 		// if he's still driving data low after 10 clocks, abort
153 		value = tl_read_i2c_data(GPIOin);	// read status
154 		if (!(value & 0x08))
155 			return 0;
156 	}
157 
158 	// To START, bring data low while clock high
159 	tl_write_i2c_reg(GPIOout, SET_CLOCK_HI | SET_DATA_LO);
160 
161 	udelay(5);
162 
163 	return 1;		// TX start successful
164 }
165 
166 //-----------------------------------------------------------------------------
167 //
168 //      Name:   tl_i2c_tx_stop
169 //
170 //      This routine transmits a stop condition over the I2C bus.
171 //
172 //-----------------------------------------------------------------------------
173 
tl_i2c_tx_stop(void * GPIOin,void * GPIOout)174 static unsigned short tl_i2c_tx_stop(void *GPIOin, void *GPIOout)
175 {
176 	int i;
177 
178 	for (i = 0; i < 10; i++) {
179 		// Send clock pulse, drive data line low
180 		tl_i2c_clock_pulse(SET_DATA_LO, GPIOout);
181 
182 		// To STOP, bring data high while clock high
183 		tl_write_i2c_reg(GPIOout, SET_DATA_HI | SET_CLOCK_HI);
184 
185 		// Give the data line time to float high
186 		udelay(5);
187 
188 		// If slave is driving data line low, there's a problem; retry
189 		if (tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)
190 			return 1;	// TX STOP successful!
191 	}
192 
193 	return 0;		// error
194 }
195 
196 //-----------------------------------------------------------------------------
197 //
198 //      Name:   tl_i2c_tx_byte
199 //
200 //      This routine transmits a byte across the I2C bus.
201 //
202 //-----------------------------------------------------------------------------
tl_i2c_tx_byte(void * GPIOout,u8 data)203 static void tl_i2c_tx_byte(void *GPIOout, u8 data)
204 {
205 	u8 bit;
206 
207 	for (bit = 0x80; bit; bit >>= 1) {
208 		if (data & bit)
209 			tl_i2c_clock_pulse((u8) SET_DATA_HI, GPIOout);
210 		else
211 			tl_i2c_clock_pulse((u8) SET_DATA_LO, GPIOout);
212 	}
213 }
214 
215 //-----------------------------------------------------------------------------
216 //
217 //      Name:   tl_i2c_rx_byte
218 //
219 //      This routine receives a byte across the I2C bus.
220 //
221 //-----------------------------------------------------------------------------
tl_i2c_rx_byte(void * GPIOin,void * GPIOout)222 static u8 tl_i2c_rx_byte(void *GPIOin, void *GPIOout)
223 {
224 	u8 bit;
225 	u8 data = 0;
226 
227 
228 	for (bit = 0x80; bit; bit >>= 1) {
229 		// do clock pulse, let data line float high
230 		tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
231 
232 		// read data line
233 		if (tl_read_i2c_data(GPIOin) & 0x08)
234 			data |= bit;
235 	}
236 
237 	return (data);
238 }
239 
240 //*****************************************************************************
241 //*****************************************************************************
242 // Function:   read_i2c_nvram
243 // Arguments:  u8 count     number of bytes to read
244 //             u8 *buf      area to store the bytes read
245 // Returns:    0 - failed
246 //             1 - success
247 //*****************************************************************************
248 //*****************************************************************************
cpqfcTS_ReadNVRAM(void * GPIOin,void * GPIOout,u16 count,u8 * buf)249 unsigned long cpqfcTS_ReadNVRAM(void *GPIOin, void *GPIOout, u16 count, u8 * buf)
250 {
251 	unsigned short i;
252 
253 	if (!(tl_i2c_tx_start(GPIOin, GPIOout)))
254 		return 0;
255 
256 	// Select the NVRAM for "dummy" write, to set the address
257 	tl_i2c_tx_byte(GPIOout, SLAVE_WRITE_ADDRESS);
258 	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
259 		return 0;
260 
261 	// Now send the address where we want to start reading
262 	tl_i2c_tx_byte(GPIOout, 0);
263 	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
264 		return 0;
265 
266 	// Send a repeated start condition and select the
267 	//  slave for reading now.
268 	if (tl_i2c_tx_start(GPIOin, GPIOout))
269 		tl_i2c_tx_byte(GPIOout, SLAVE_READ_ADDRESS);
270 
271 	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
272 		return 0;
273 
274 	// this loop will now read out the data and store it
275 	//  in the buffer pointed to by buf
276 	for (i = 0; i < count; i++) {
277 		*buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
278 
279 		// Send ACK by holding data line low for 1 clock
280 		if (i < (count - 1))
281 			tl_i2c_clock_pulse(0x08, GPIOout);
282 		else {
283 			// Don't send ack for final byte
284 			tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
285 		}
286 	}
287 
288 	tl_i2c_tx_stop(GPIOin, GPIOout);
289 
290 	return 1;
291 }
292 
293 //****************************************************************
294 //
295 //
296 //
297 // routines to set and clear the data and clock bits
298 //
299 //
300 //
301 //****************************************************************
302 
tl_set_clock(void * gpioreg)303 static void tl_set_clock(void *gpioreg)
304 {
305 	u32 ret_val;
306 
307 	ret_val = readl(gpioreg);
308 	ret_val &= 0xffffffFBL;	// clear GPIO2 (SCL)
309 	writel(ret_val, gpioreg);
310 }
311 
tl_clr_clock(void * gpioreg)312 static void tl_clr_clock(void *gpioreg)
313 {
314 	u32 ret_val;
315 
316 	ret_val = readl(gpioreg);
317 	ret_val |= SET_CLOCK_LO;
318 	writel(ret_val, gpioreg);
319 }
320 
321 //*****************************************************************
322 //
323 //
324 // This routine will advance the clock by one period
325 //
326 //
327 //*****************************************************************
tl_i2c_clock_pulse(u8 value,void * GPIOout)328 static void tl_i2c_clock_pulse(u8 value, void *GPIOout)
329 {
330 	u32 ret_val;
331 
332 	// clear the clock bit
333 	tl_clr_clock(GPIOout);
334 
335 	udelay(5);
336 
337 
338 	// read the port to preserve non-I2C bits
339 	ret_val = readl(GPIOout);
340 
341 	// clear the data & clock bits
342 	ret_val &= 0xFFFFFFf3;
343 
344 	// write the value passed in...
345 	// data can only change while clock is LOW!
346 	ret_val |= value;	// the data
347 	ret_val |= SET_CLOCK_LO;	// the clock
348 	writel(ret_val, GPIOout);
349 
350 	udelay(5);
351 
352 
353 	//set clock bit
354 	tl_set_clock(GPIOout);
355 }
356 
357 
358 
359 
360 //*****************************************************************
361 //
362 //
363 // This routine returns the 64-bit WWN
364 //
365 //
366 //*****************************************************************
cpqfcTS_GetNVRAM_data(u8 * wwnbuf,u8 * buf)367 int cpqfcTS_GetNVRAM_data(u8 * wwnbuf, u8 * buf)
368 {
369 	u32 len;
370 	u32 sub_len;
371 	u32 ptr_inc;
372 	u32 i;
373 	u32 j;
374 	u8 *data_ptr;
375 	u8 z;
376 	u8 name;
377 	u8 sub_name;
378 	u8 done;
379 	int ret = 0;	// def. 0 offset is failure to find WWN field
380 
381 
382 
383 	data_ptr = (u8 *) buf;
384 
385 	done = 0;
386 	i = 0;
387 
388 	while (i < 128 && !done) {
389 		z = data_ptr[i];
390 		if (!(z & 0x80)) {
391 			len = 1 + (z & 0x07);
392 
393 			name = (z & 0x78) >> 3;
394 			if (name == 0x0F)
395 				done = 1;
396 		} else {
397 			name = z & 0x7F;
398 			len = 3 + data_ptr[i + 1] + (data_ptr[i + 2] << 8);
399 
400 			switch (name) {
401 			case 0x0D:
402 				//
403 				j = i + 3;
404 				//
405 				if (data_ptr[j] == 0x3b) {
406 					len = 6;
407 					break;
408 				}
409 
410 				while (j < (i + len)) {
411 					sub_name = (data_ptr[j] & 0x3f);
412 					sub_len = data_ptr[j + 1] + (data_ptr[j + 2] << 8);
413 					ptr_inc = sub_len + 3;
414 					switch (sub_name) {
415 					case 0x3C:
416 						memcpy(wwnbuf, &data_ptr[j + 3], 8);
417 						ret = j + 3;
418 						break;
419 					default:
420 						break;
421 					}
422 					j += ptr_inc;
423 				}
424 				break;
425 			default:
426 				break;
427 			}
428 		}
429 		//
430 		i += len;
431 	}			// end while
432 	return ret;
433 }
434 
435