Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.13-rc4 493 lines 13 kB view raw
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> 28enum boolean { FALSE, TRUE } ; 29 30 31#ifndef UCHAR 32typedef __u8 UCHAR; 33#endif 34#ifndef BOOLEAN 35typedef __u8 BOOLEAN; 36#endif 37#ifndef USHORT 38typedef __u16 USHORT; 39#endif 40#ifndef ULONG 41typedef __u32 ULONG; 42#endif 43 44 45#include <linux/string.h> 46#include <linux/pci.h> 47#include <linux/delay.h> 48#include <linux/sched.h> 49#include <asm/io.h> // struct pt_regs for IRQ handler & Port I/O 50 51#include "cpqfcTSchip.h" 52 53static void tl_i2c_tx_byte( void* GPIOout, UCHAR data ); 54/*static BOOLEAN tl_write_i2c_page_portion( void* GPIOin, void* GPIOout, 55 USHORT startOffset, // e.g. 0x2f for WWN start 56 USHORT count, 57 UCHAR *buf ); 58*/ 59 60// 61// Tachlite GPIO2, GPIO3 (I2C) DEFINES 62// The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data) 63// GPIO2 drives SDA, and GPIO3 drives SCL 64// 65// Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0 66// and clear writes 1. The input lines (read in TL status) is NOT inverted 67// This really helps confuse the code and debugging. 68 69#define SET_DATA_HI 0x0 70#define SET_DATA_LO 0x8 71#define SET_CLOCK_HI 0x0 72#define SET_CLOCK_LO 0x4 73 74#define SENSE_DATA_HI 0x8 75#define SENSE_DATA_LO 0x0 76#define SENSE_CLOCK_HI 0x4 77#define SENSE_CLOCK_LO 0x0 78 79#define SLAVE_READ_ADDRESS 0xA1 80#define SLAVE_WRITE_ADDRESS 0xA0 81 82 83static void i2c_delay(ULONG mstime); 84static void tl_i2c_clock_pulse( UCHAR , void* GPIOout); 85static UCHAR tl_read_i2c_data( void* ); 86 87 88//----------------------------------------------------------------------------- 89// 90// Name: I2C_RX_ACK 91// 92// This routine receives an acknowledge over the I2C bus. 93// 94//----------------------------------------------------------------------------- 95static unsigned short tl_i2c_rx_ack( void* GPIOin, void* GPIOout ) 96{ 97 unsigned long value; 98 99 // do clock pulse, let data line float high 100 tl_i2c_clock_pulse( SET_DATA_HI, GPIOout ); 101 102 // slave must drive data low for acknowledge 103 value = tl_read_i2c_data( GPIOin); 104 if (value & SENSE_DATA_HI ) 105 return( FALSE ); 106 107 return( TRUE ); 108} 109//----------------------------------------------------------------------------- 110// 111// Name: READ_I2C_REG 112// 113// This routine reads the I2C control register using the global 114// IO address stored in gpioreg. 115// 116//----------------------------------------------------------------------------- 117static UCHAR tl_read_i2c_data( void* gpioreg ) 118{ 119 return( (UCHAR)(readl( gpioreg ) & 0x08L) ); // GPIO3 120} 121//----------------------------------------------------------------------------- 122// 123// Name: WRITE_I2C_REG 124// 125// This routine writes the I2C control register using the global 126// IO address stored in gpioreg. 127// In Tachlite, we don't want to modify other bits in TL Control reg. 128// 129//----------------------------------------------------------------------------- 130static void tl_write_i2c_reg( void* gpioregOUT, UCHAR value ) 131{ 132 ULONG temp; 133 134 // First read the register and clear out the old bits 135 temp = readl( gpioregOUT ) & 0xfffffff3L; 136 137 // Now or in the new data and send it back out 138 writel( temp | value, gpioregOUT); 139} 140//----------------------------------------------------------------------------- 141// 142// Name: I2C_TX_START 143// 144// This routine transmits a start condition over the I2C bus. 145// 1. Set SCL (clock, GPIO2) HIGH, set SDA (data, GPIO3) HIGH, 146// wait 5us to stabilize. 147// 2. With SCL still HIGH, drive SDA low. The low transition marks 148// the start condition to NM24Cxx (the chip) 149// NOTE! In TL control reg., output 1 means chip sees LOW 150// 151//----------------------------------------------------------------------------- 152static unsigned short tl_i2c_tx_start( void* GPIOin, void* GPIOout ) 153{ 154 unsigned short i; 155 ULONG value; 156 157 if ( !(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)) 158 { 159 // start with clock high, let data float high 160 tl_write_i2c_reg( GPIOout, SET_DATA_HI | SET_CLOCK_HI ); 161 162 // keep sending clock pulses if slave is driving data line 163 for (i = 0; i < 10; i++) 164 { 165 tl_i2c_clock_pulse( SET_DATA_HI, GPIOout ); 166 167 if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI ) 168 break; 169 } 170 171 // if he's still driving data low after 10 clocks, abort 172 value = tl_read_i2c_data( GPIOin ); // read status 173 if (!(value & 0x08) ) 174 return( FALSE ); 175 } 176 177 178 // To START, bring data low while clock high 179 tl_write_i2c_reg( GPIOout, SET_CLOCK_HI | SET_DATA_LO ); 180 181 i2c_delay(0); 182 183 return( TRUE ); // TX start successful 184} 185//----------------------------------------------------------------------------- 186// 187// Name: I2C_TX_STOP 188// 189// This routine transmits a stop condition over the I2C bus. 190// 191//----------------------------------------------------------------------------- 192 193static unsigned short tl_i2c_tx_stop( void* GPIOin, void* GPIOout ) 194{ 195 int i; 196 197 for (i = 0; i < 10; i++) 198 { 199 // Send clock pulse, drive data line low 200 tl_i2c_clock_pulse( SET_DATA_LO, GPIOout ); 201 202 // To STOP, bring data high while clock high 203 tl_write_i2c_reg( GPIOout, SET_DATA_HI | SET_CLOCK_HI ); 204 205 // Give the data line time to float high 206 i2c_delay(0); 207 208 // If slave is driving data line low, there's a problem; retry 209 if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI ) 210 return( TRUE ); // TX STOP successful! 211 } 212 213 return( FALSE ); // error 214} 215//----------------------------------------------------------------------------- 216// 217// Name: I2C_TX_uchar 218// 219// This routine transmits a byte across the I2C bus. 220// 221//----------------------------------------------------------------------------- 222static void tl_i2c_tx_byte( void* GPIOout, UCHAR data ) 223{ 224 UCHAR bit; 225 226 for (bit = 0x80; bit; bit >>= 1) 227 { 228 if( data & bit ) 229 tl_i2c_clock_pulse( (UCHAR)SET_DATA_HI, GPIOout); 230 else 231 tl_i2c_clock_pulse( (UCHAR)SET_DATA_LO, GPIOout); 232 } 233} 234//----------------------------------------------------------------------------- 235// 236// Name: I2C_RX_uchar 237// 238// This routine receives a byte across the I2C bus. 239// 240//----------------------------------------------------------------------------- 241static UCHAR tl_i2c_rx_byte( void* GPIOin, void* GPIOout ) 242{ 243 UCHAR bit; 244 UCHAR data = 0; 245 246 247 for (bit = 0x80; bit; bit >>= 1) { 248 // do clock pulse, let data line float high 249 tl_i2c_clock_pulse( SET_DATA_HI, GPIOout ); 250 251 // read data line 252 if ( tl_read_i2c_data( GPIOin) & 0x08 ) 253 data |= bit; 254 } 255 256 return (data); 257} 258//***************************************************************************** 259//***************************************************************************** 260// Function: read_i2c_nvram 261// Arguments: UCHAR count number of bytes to read 262// UCHAR *buf area to store the bytes read 263// Returns: 0 - failed 264// 1 - success 265//***************************************************************************** 266//***************************************************************************** 267unsigned long cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count, 268 UCHAR *buf ) 269{ 270 unsigned short i; 271 272 if( !( tl_i2c_tx_start(GPIOin, GPIOout) )) 273 return FALSE; 274 275 // Select the NVRAM for "dummy" write, to set the address 276 tl_i2c_tx_byte( GPIOout , SLAVE_WRITE_ADDRESS ); 277 if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) ) 278 return( FALSE ); 279 280 // Now send the address where we want to start reading 281 tl_i2c_tx_byte( GPIOout , 0 ); 282 if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) ) 283 return( FALSE ); 284 285 // Send a repeated start condition and select the 286 // slave for reading now. 287 if( tl_i2c_tx_start(GPIOin, GPIOout) ) 288 tl_i2c_tx_byte( GPIOout, SLAVE_READ_ADDRESS ); 289 290 if ( !tl_i2c_rx_ack(GPIOin, GPIOout) ) 291 return( FALSE ); 292 293 // this loop will now read out the data and store it 294 // in the buffer pointed to by buf 295 for ( i=0; i<count; i++) 296 { 297 *buf++ = tl_i2c_rx_byte(GPIOin, GPIOout); 298 299 // Send ACK by holding data line low for 1 clock 300 if ( i < (count-1) ) 301 tl_i2c_clock_pulse( 0x08, GPIOout ); 302 else { 303 // Don't send ack for final byte 304 tl_i2c_clock_pulse( SET_DATA_HI, GPIOout ); 305 } 306 } 307 308 tl_i2c_tx_stop(GPIOin, GPIOout); 309 310 return( TRUE ); 311} 312 313//**************************************************************** 314// 315// 316// 317// routines to set and clear the data and clock bits 318// 319// 320// 321//**************************************************************** 322 323static void tl_set_clock(void* gpioreg) 324{ 325 ULONG ret_val; 326 327 ret_val = readl( gpioreg ); 328 ret_val &= 0xffffffFBL; // clear GPIO2 (SCL) 329 writel( ret_val, gpioreg); 330} 331 332static void tl_clr_clock(void* gpioreg) 333{ 334 ULONG ret_val; 335 336 ret_val = readl( gpioreg ); 337 ret_val |= SET_CLOCK_LO; 338 writel( ret_val, gpioreg); 339} 340 341//***************************************************************** 342// 343// 344// This routine will advance the clock by one period 345// 346// 347//***************************************************************** 348static void tl_i2c_clock_pulse( UCHAR value, void* GPIOout ) 349{ 350 ULONG ret_val; 351 352 // clear the clock bit 353 tl_clr_clock( GPIOout ); 354 355 i2c_delay(0); 356 357 358 // read the port to preserve non-I2C bits 359 ret_val = readl( GPIOout ); 360 361 // clear the data & clock bits 362 ret_val &= 0xFFFFFFf3; 363 364 // write the value passed in... 365 // data can only change while clock is LOW! 366 ret_val |= value; // the data 367 ret_val |= SET_CLOCK_LO; // the clock 368 writel( ret_val, GPIOout ); 369 370 i2c_delay(0); 371 372 373 //set clock bit 374 tl_set_clock( GPIOout); 375} 376 377 378 379 380//***************************************************************** 381// 382// 383// This routine returns the 64-bit WWN 384// 385// 386//***************************************************************** 387int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf ) 388{ 389 ULONG len; 390 ULONG sub_len; 391 ULONG ptr_inc; 392 ULONG i; 393 ULONG j; 394 UCHAR *data_ptr; 395 UCHAR z; 396 UCHAR name; 397 UCHAR sub_name; 398 UCHAR done; 399 int iReturn=0; // def. 0 offset is failure to find WWN field 400 401 402 403 data_ptr = (UCHAR *)buf; 404 405 done = FALSE; 406 i = 0; 407 408 while ( (i < 128) && (!done) ) 409 { 410 z = data_ptr[i];\ 411 if ( !(z & 0x80) ) 412 { 413 len = 1 + (z & 0x07); 414 415 name = (z & 0x78) >> 3; 416 if (name == 0x0F) 417 done = TRUE; 418 } 419 else 420 { 421 name = z & 0x7F; 422 len = 3 + data_ptr[i+1] + (data_ptr[i+2] << 8); 423 424 switch (name) 425 { 426 case 0x0D: 427 // 428 j = i + 3; 429 // 430 if ( data_ptr[j] == 0x3b ) { 431 len = 6; 432 break; 433 } 434 435 while ( j<(i+len) ) { 436 sub_name = (data_ptr[j] & 0x3f); 437 sub_len = data_ptr[j+1] + 438 (data_ptr[j+2] << 8); 439 ptr_inc = sub_len + 3; 440 switch (sub_name) 441 { 442 case 0x3C: 443 memcpy( wwnbuf, &data_ptr[j+3], 8); 444 iReturn = j+3; 445 break; 446 default: 447 break; 448 } 449 j += ptr_inc; 450 } 451 break; 452 default: 453 break; 454 } 455 } 456 // 457 i += len; 458 } // end while 459 return iReturn; 460} 461 462 463 464 465 466// define a short 5 micro sec delay, and longer (ms) delay 467 468static void i2c_delay(ULONG mstime) 469{ 470 ULONG i; 471 472// NOTE: we only expect to use these delays when reading 473// our adapter's NVRAM, which happens only during adapter reset. 474// Delay technique from "Linux Device Drivers", A. Rubini 475// (1st Ed.) pg 137. 476 477// printk(" delay %lx ", mstime); 478 if( mstime ) // ms delay? 479 { 480 // delay technique 481 for( i=0; i < mstime; i++) 482 udelay(1000); // 1ms per loop 483 484 } 485 else // 5 micro sec delay 486 487 udelay( 5 ); // micro secs 488 489// printk("done\n"); 490} 491 492 493