openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

xfp.c (10515B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * BCM56xx I2C Device Driver for XFP modules.
      8  */
      9 #include <sal/types.h>
     10 #include <soc/drv.h>
     11 #include <soc/error.h>
     12 #include <soc/debug.h>
     13 #include <soc/i2c.h>
     14 #include <shared/bsl.h>
     15 #define XFP_PAGE_SIZE            1    /* Bytes per page */
     16 #define XFP_DEVICE_SIZE         (256*XFP_PAGE_SIZE) /* 256 bytes */
     17 #define XFP_ACK_RETRY_COUNT      1000  /* Number of retry polls */
     18 
     19 /*
     20  * Function: xfp_ack_poll
     21  *
     22  * Purpose:  Poll the device to determine if it is ready for IO.
     23  *           When the chip writes data, it will become unresponsive
     24  *           for a period of Time Tw (Internal Write Delay). We could
     25  *           either wait the maximum amount of time for the device to
     26  *           finish it's write-cycle (10ms), or we can poll the device
     27  *           for a specified operation (r/w) until it responds with an
     28  *           ACK. This routine polls the device until it is responsive.
     29  *
     30  * Parameters:
     31  *    unit - StrataSwitch device number or I2C bus number
     32  *    bus_addr - chip IO (I2C) slave bus address byte(s)
     33  *
     34  * Returns:
     35  *     Number of Poll operations required to contact device, or
     36  *     XFP_ACK_RETRY_COUNT if the device is not online or responding.
     37  *
     38  *
     39  * Notes:
     40  *     See also: soc_i2c_ack_poll
     41  */
     42 STATIC INLINE int
     43 xfp_ack_poll(int unit, i2c_bus_addr_t bus_addr)
     44 {
     45     return soc_i2c_ack_poll(unit, bus_addr, XFP_ACK_RETRY_COUNT);
     46 }
     47 
     48 /*
     49  * Function: xfp_read
     50  *
     51  * Purpose: Read len bytes of data into buffer, update len with total
     52  *          amount read.
     53  *
     54  * Parameters:
     55  *    unit - StrataSwitch device number or I2C bus number
     56  *    devno - chip device id
     57  *    addr - XFP memory address to read from
     58  *    data - address of data buffer to read into
     59  *    len - address containing number of bytes read into data buffer (updated
     60  *          with number of bytes read on completion).
     61  *
     62  * Returns: data bufffer filled in with data from address, number of
     63  *          bytes read is updated in len field. Status code:
     64  *
     65  *          SOC_E_NONE -- no error encounter
     66  *          SOC_E_TIMEOUT - chip timeout or data error
     67  *
     68  * Notes:
     69  *         Currently uses random address byte read to initiate the read; if
     70  *         more than one byte of data is requested at the current address, a
     71  *         sequential read operation is performed.
     72  */
     73 STATIC int
     74 xfp_read(int unit, int devno,
     75 	      uint16 addr, uint8* data, uint32 *len)
     76 {
     77     int rv = SOC_E_NONE;
     78     uint8 saddr_r, saddr_w, a0;
     79     uint32 nbytes = 0;
     80 
     81     /* Valid address, memory and size must be provided */
     82     if ( ! len || ! data )
     83 	return SOC_E_PARAM;
     84 
     85     I2C_LOCK(unit);
     86 
     87     saddr_r = SOC_I2C_RX_ADDR(soc_i2c_addr(unit, devno));
     88     saddr_w = SOC_I2C_TX_ADDR(soc_i2c_addr(unit, devno));
     89 
     90     a0 = (uint8) (addr & 0x00ff);
     91 
     92     LOG_INFO(BSL_LS_SOC_I2C,
     93              (BSL_META_U(unit,
     94                          "xfp_read: addr=0x%x (a0=0x%x) len=%d\n"),
     95               addr, a0, (int)*len));
     96 
     97     /* First, we put out the address which we would like to
     98      * read at using the SOC_I2C_TX_ADDR (saddr_w)
     99      */
    100     if ( (rv = soc_i2c_start(unit, saddr_w)) < 0) {
    101         LOG_INFO(BSL_LS_SOC_I2C,
    102                  (BSL_META_U(unit,
    103                              "xfp_read(%d,%d,%x,%p,%d): "
    104                              "failed to generate start.\n"),
    105                   unit, devno, addr, (void *)data, *len));
    106 	I2C_UNLOCK(unit);
    107 	return rv;
    108     }
    109 
    110     if( (rv = soc_i2c_write_one_byte(unit, a0)) < 0) {
    111         LOG_INFO(BSL_LS_SOC_I2C,
    112                  (BSL_META_U(unit,
    113                              "xfp_read(%d,%d,%x,%p,%d): "
    114                              "failed to send a0 byte.\n"),
    115                   unit, devno, addr, (void *)data, *len));
    116 
    117 	goto error;
    118     }
    119     /* Now, we have sent the first and second word addresses,
    120      * we then issue a repeated start condition, followed by
    121      * the device's read address (note: saddr_r)
    122      */
    123     if( (rv = soc_i2c_rep_start(unit, saddr_r)) < 0) {
    124         LOG_INFO(BSL_LS_SOC_I2C,
    125                  (BSL_META_U(unit,
    126                              "xfp_read(%d,%d,%x,%p,%d): "
    127                              "failed to generate rep start.\n"),
    128                   unit, devno, addr, (void *)data, *len));
    129 	goto error;
    130     }
    131     nbytes = *len;
    132     if ( (rv = soc_i2c_read_bytes(unit, data, (int *)&nbytes, 0) ) < 0 ) {
    133 	goto error;
    134     }
    135     *len = nbytes;
    136 
    137  error:
    138 
    139     soc_i2c_stop(unit);
    140 
    141     I2C_UNLOCK(unit);
    142     return rv ;
    143 }
    144 
    145 /*
    146  * Function: xfp_write
    147  * Purpose: Write len bytes of data, return the number of bytes written.
    148  * Uses PAGE mode to write up to 32 bytes at a time between address
    149  * stages for maximum performance.
    150  *
    151  * Parameters:
    152  *    unit - StrataSwitch device number or I2C bus number
    153  *    devno - chip device id
    154  *    addr - XFP memory address to write to
    155  *    data - address of data buffer to write from
    156  *    len - number of bytes to write
    157  *
    158  * Returns:
    159  *          SOC_E_NONE -- no error encountered
    160  *          SOC_E_TIMEOUT - chip timeout or data error
    161  *
    162  *
    163  * Notes:
    164  *     Uses page mode to write in 32-byte chunks, when an address
    165  *     which does not begin on a page boundary is provided, the write
    166  *     operation handles unaligned accesses by breaking up the write
    167  *     into one write which is not page aligned, and the remainder as
    168  *     page aligned accesses.
    169  */
    170 STATIC int
    171 xfp_write(int unit, int devno,
    172 	      uint16 addr, uint8* data, uint32 len)
    173 {
    174     int rv = SOC_E_NONE;
    175     uint8 *ptr, a0;
    176     uint32 b, numpages, cpage, nbytes, tbytes, caddr;
    177     i2c_bus_addr_t bus_addr;
    178 
    179     /* User must have data to write */
    180     if ( ! data || len <= 0 )
    181 	return SOC_E_PARAM;
    182 
    183     I2C_LOCK(unit);
    184 
    185     /* Use PAGE mode */
    186     caddr = addr;
    187     numpages = len / XFP_PAGE_SIZE + (len % XFP_PAGE_SIZE > 0);
    188     ptr = data;
    189 
    190 
    191     tbytes = soc_i2c_device(unit, devno)->tbyte++;
    192 
    193     bus_addr = SOC_I2C_TX_ADDR(soc_i2c_addr(unit, devno));
    194 
    195     LOG_INFO(BSL_LS_SOC_I2C,
    196              (BSL_META_U(unit,
    197                          "xfp_write: addr=0x%x data=%p len=%d npages=%d\n"),
    198               caddr, (void *)data, (int)len, numpages));
    199 
    200     /* Loop over every page in buffer .. */
    201     for(cpage = 0; cpage < numpages; cpage++){
    202 	/* Address not page aligned, D'Oh, can't write a full page. */
    203 	if( (caddr % XFP_PAGE_SIZE) != 0){
    204         /* coverity[dead_error_begin] */
    205 	    nbytes = XFP_PAGE_SIZE - (caddr % XFP_PAGE_SIZE);
    206 	    len -= nbytes;
    207 	} else {
    208 	    /* Address is page aligned, calculate bytes to write */
    209 	    if ( len <= XFP_PAGE_SIZE ) {
    210 	        /* Less than a page to write */
    211 		nbytes = len;
    212 	    } else {
    213 		/* Wammo, full page write */
    214 		nbytes = XFP_PAGE_SIZE;
    215 		len -= nbytes;
    216 	    }
    217 	}
    218 
    219 	/* Construct device address bytes */
    220 	a0 = (uint8) (caddr & 0x00ff);
    221 
    222 	LOG_INFO(BSL_LS_SOC_I2C,
    223                  (BSL_META_U(unit,
    224                              "xfp_write: unit=%d cpage=%d START on page_addr=0x%x"
    225                              " nbytes=%d\n"), unit, cpage, caddr, nbytes));
    226 
    227 	/* Generate Start, for Write address */
    228 	if( (rv = soc_i2c_start(unit, bus_addr)) < 0){
    229 	    LOG_INFO(BSL_LS_SOC_I2C,
    230                      (BSL_META_U(unit,
    231                                  "xfp_write(%d,%d,%x,%d,%d): "
    232                                  "failed to gen start\n"),
    233                       unit, devno, caddr, *data, len));
    234 	    I2C_UNLOCK(unit);
    235 	    return rv;
    236 	}
    237 
    238 	/* Send LSB (a0), wait for ACK */
    239 	if( (rv = soc_i2c_write_one_byte(unit, a0)) < 0){
    240 	    LOG_INFO(BSL_LS_SOC_I2C,
    241                      (BSL_META_U(unit,
    242                                  "xfp_write(%d,%d,%x,%d,%d): "
    243                                  "failed to send a0 byte\n"),
    244                       unit, devno, caddr, *data, len));
    245 	    goto error;
    246 	}
    247 	/* Send up to PAGE_SIZE data bytes, wait for ACK */
    248 	for ( b = 0; b < nbytes; b++, ptr++, caddr++ ) {
    249 	    if ( (rv = soc_i2c_write_one_byte(unit, *ptr)) < 0){
    250             LOG_INFO(BSL_LS_SOC_I2C,
    251                      (BSL_META_U(unit,
    252                                  "xfp_write(%d,%d,%d,%d,%d): "
    253                                  "tx data byte error\n"),
    254                       unit, devno, caddr, (uint32)*ptr, b));
    255 		goto error;
    256 	    }
    257 	    LOG_VERBOSE(BSL_LS_SOC_I2C,
    258                         (BSL_META_U(unit,
    259                                     "xfp_write(u=%d,id=%d,page=%d "
    260                                     "caddr=%d,data=0x%x,idx=%d)\n"),
    261                          unit, devno, cpage, caddr, (uint8)*ptr, b));
    262 
    263 	    soc_i2c_device(unit, devno)->tbyte++;
    264 	}
    265 
    266 	/* Send STOP, also what we do on an error to free bus.. */
    267     error:
    268 
    269 	soc_i2c_stop(unit);
    270 
    271 	/* Acknowledge polling: When the chip enters it's
    272 	 * own internal write-cycle, it falls off the I2C bus
    273 	 * and does not ACK a start/address phase; hence, we
    274 	 * attempt addressing the chip until it responds, at
    275 	 * which point the internal write cycle has finished.
    276 	 */
    277 	rv = xfp_ack_poll(unit, bus_addr);
    278 	LOG_INFO(BSL_LS_SOC_I2C,
    279                  (BSL_META_U(unit,
    280                              "xfp_ack_poll: "
    281                              "%d address cycles for wr latency.\n"), rv));
    282 	rv = (rv > 0 ? SOC_E_NONE: SOC_E_TIMEOUT);
    283 
    284     }
    285 
    286     I2C_UNLOCK(unit);
    287 
    288     if (rv >= 0) {
    289         return soc_i2c_device(unit, devno)->tbyte - tbytes - 1 ;
    290     } else {
    291         return (rv);
    292     }
    293 }
    294 
    295 
    296 /*
    297  * Function: xfp_init
    298  *
    299  * Purpose: initialize the XFP I2C interface.
    300  *
    301  * Parameters:
    302  *    unit - StrataSwitch device number or I2C bus number
    303  *    devno - chip device id
    304  *    data - address of test data
    305  *    len - size of test data
    306  */
    307 STATIC int
    308 xfp_init(int unit, int devno, void* data, int len)
    309 {
    310     soc_i2c_devdesc_set(unit, devno, "XFP");
    311 
    312     return SOC_E_NONE;
    313 }
    314 
    315 /*
    316  * Function: xfp_ioctl: does miscellaenous tasks.
    317  * Purpose: Support miscellaneous chip options.
    318  *
    319  * Parameters:
    320  *    unit - StrataSwitch device number or I2C bus number
    321  *    devno - chip device id
    322  *    command - IO control operation
    323  *    data - address of user data
    324  *    len - size of test data
    325  *
    326  * Notes:
    327  *   Placeholder for write Protect, EEPROM Chip reset - NYI
    328  */
    329 STATIC int
    330 xfp_ioctl(int unit, int devno,
    331 	       int command, void* data, int len)
    332 {
    333     switch ( command ) {
    334 
    335     default:
    336 	break;
    337     }
    338     return SOC_E_NONE;
    339 }
    340 
    341 /* XFP Driver callout */
    342 i2c_driver_t _soc_i2c_xfp_driver = {
    343     0x0,0x0, /* System assigned bytes */
    344     XFP_DEVICE_TYPE,
    345     xfp_read,
    346     xfp_write,
    347     xfp_ioctl,
    348     xfp_init,
    349     NULL,
    350 };