1 /* Copyright(c) 2000, Compaq Computer Corporation
2 * Fibre Channel Host Bus Adapter
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
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
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
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
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
34 #include "cpqfcTSchip.h"
36 static void tl_i2c_tx_byte(void *GPIOout, u8 data);
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
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.
48 #define SET_DATA_HI 0x0
49 #define SET_DATA_LO 0x8
50 #define SET_CLOCK_HI 0x0
51 #define SET_CLOCK_LO 0x4
53 #define SENSE_DATA_HI 0x8
54 #define SENSE_DATA_LO 0x0
55 #define SENSE_CLOCK_HI 0x4
56 #define SENSE_CLOCK_LO 0x0
58 #define SLAVE_READ_ADDRESS 0xA1
59 #define SLAVE_WRITE_ADDRESS 0xA0
62 static void tl_i2c_clock_pulse(u8, void *GPIOout);
63 static u8 tl_read_i2c_data(void *);
66 //-----------------------------------------------------------------------------
68 // Name: tl_i2c_rx_ack
70 // This routine receives an acknowledge over the I2C bus.
72 //-----------------------------------------------------------------------------
73 static unsigned short tl_i2c_rx_ack(void *GPIOin, void *GPIOout)
77 // do clock pulse, let data line float high
78 tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
80 // slave must drive data low for acknowledge
81 value = tl_read_i2c_data(GPIOin);
82 if (value & SENSE_DATA_HI)
88 //-----------------------------------------------------------------------------
90 // Name: tl_read_i2c_reg
92 // This routine reads the I2C control register using the global
93 // IO address stored in gpioreg.
95 //-----------------------------------------------------------------------------
96 static u8 tl_read_i2c_data(void *gpioreg)
98 return ((u8) (readl(gpioreg) & 0x08L)); // GPIO3
101 //-----------------------------------------------------------------------------
103 // Name: tl_write_i2c_reg
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.
109 //-----------------------------------------------------------------------------
110 static void tl_write_i2c_reg(void *gpioregOUT, u8 value)
114 // First read the register and clear out the old bits
115 temp = readl(gpioregOUT) & 0xfffffff3L;
117 // Now or in the new data and send it back out
118 writel(temp | value, gpioregOUT);
120 /* PCI posting ???? */
123 //-----------------------------------------------------------------------------
125 // Name: tl_i2c_tx_start
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
134 //-----------------------------------------------------------------------------
135 static unsigned short tl_i2c_tx_start(void *GPIOin, void *GPIOout)
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);
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);
148 if (tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)
152 // if he's still driving data low after 10 clocks, abort
153 value = tl_read_i2c_data(GPIOin); // read status
158 // To START, bring data low while clock high
159 tl_write_i2c_reg(GPIOout, SET_CLOCK_HI | SET_DATA_LO);
163 return 1; // TX start successful
166 //-----------------------------------------------------------------------------
168 // Name: tl_i2c_tx_stop
170 // This routine transmits a stop condition over the I2C bus.
172 //-----------------------------------------------------------------------------
174 static unsigned short tl_i2c_tx_stop(void *GPIOin, void *GPIOout)
178 for (i = 0; i < 10; i++) {
179 // Send clock pulse, drive data line low
180 tl_i2c_clock_pulse(SET_DATA_LO, GPIOout);
182 // To STOP, bring data high while clock high
183 tl_write_i2c_reg(GPIOout, SET_DATA_HI | SET_CLOCK_HI);
185 // Give the data line time to float high
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!
196 //-----------------------------------------------------------------------------
198 // Name: tl_i2c_tx_byte
200 // This routine transmits a byte across the I2C bus.
202 //-----------------------------------------------------------------------------
203 static void tl_i2c_tx_byte(void *GPIOout, u8 data)
207 for (bit = 0x80; bit; bit >>= 1) {
209 tl_i2c_clock_pulse((u8) SET_DATA_HI, GPIOout);
211 tl_i2c_clock_pulse((u8) SET_DATA_LO, GPIOout);
215 //-----------------------------------------------------------------------------
217 // Name: tl_i2c_rx_byte
219 // This routine receives a byte across the I2C bus.
221 //-----------------------------------------------------------------------------
222 static u8 tl_i2c_rx_byte(void *GPIOin, void *GPIOout)
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);
233 if (tl_read_i2c_data(GPIOin) & 0x08)
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
247 //*****************************************************************************
248 //*****************************************************************************
249 unsigned long cpqfcTS_ReadNVRAM(void *GPIOin, void *GPIOout, u16 count, u8 * buf)
253 if (!(tl_i2c_tx_start(GPIOin, GPIOout)))
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))
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))
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);
271 if (!tl_i2c_rx_ack(GPIOin, GPIOout))
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);
279 // Send ACK by holding data line low for 1 clock
281 tl_i2c_clock_pulse(0x08, GPIOout);
283 // Don't send ack for final byte
284 tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
288 tl_i2c_tx_stop(GPIOin, GPIOout);
293 //****************************************************************
297 // routines to set and clear the data and clock bits
301 //****************************************************************
303 static void tl_set_clock(void *gpioreg)
307 ret_val = readl(gpioreg);
308 ret_val &= 0xffffffFBL; // clear GPIO2 (SCL)
309 writel(ret_val, gpioreg);
312 static void tl_clr_clock(void *gpioreg)
316 ret_val = readl(gpioreg);
317 ret_val |= SET_CLOCK_LO;
318 writel(ret_val, gpioreg);
321 //*****************************************************************
324 // This routine will advance the clock by one period
327 //*****************************************************************
328 static void tl_i2c_clock_pulse(u8 value, void *GPIOout)
332 // clear the clock bit
333 tl_clr_clock(GPIOout);
338 // read the port to preserve non-I2C bits
339 ret_val = readl(GPIOout);
341 // clear the data & clock bits
342 ret_val &= 0xFFFFFFf3;
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);
354 tl_set_clock(GPIOout);
360 //*****************************************************************
363 // This routine returns the 64-bit WWN
366 //*****************************************************************
367 int cpqfcTS_GetNVRAM_data(u8 * wwnbuf, u8 * buf)
379 int ret = 0; // def. 0 offset is failure to find WWN field
383 data_ptr = (u8 *) buf;
388 while (i < 128 && !done) {
391 len = 1 + (z & 0x07);
393 name = (z & 0x78) >> 3;
398 len = 3 + data_ptr[i + 1] + (data_ptr[i + 2] << 8);
405 if (data_ptr[j] == 0x3b) {
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;
416 memcpy(wwnbuf, &data_ptr[j + 3], 8);