1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 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 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #ifndef _IXGBE_BYPASS_API_H_ 35 #define _IXGBE_BYPASS_API_H_ 36 37 #ifdef RTE_LIBRTE_IXGBE_BYPASS 38 39 #include "ixgbe_bypass_defines.h" 40 /** 41 * ixgbe_bypass_rw_generic - Bit bang data into by_pass FW 42 * 43 * @hw: pointer to hardware structure 44 * @cmd: Command we send to the FW 45 * @status: The reply from the FW 46 * 47 * Bit-bangs the cmd to the by_pass FW status points to what is returned. 48 **/ 49 #define IXGBE_BYPASS_BB_WAIT 1 50 static s32 ixgbe_bypass_rw_generic(struct ixgbe_hw *hw, u32 cmd, u32 *status) 51 { 52 int i; 53 u32 sck, sdi, sdo, dir_sck, dir_sdi, dir_sdo; 54 u32 esdp; 55 56 if (!status) 57 return IXGBE_ERR_PARAM; 58 59 *status = 0; 60 61 /* SDP vary by MAC type */ 62 switch (hw->mac.type) { 63 case ixgbe_mac_82599EB: 64 sck = IXGBE_ESDP_SDP7; 65 sdi = IXGBE_ESDP_SDP0; 66 sdo = IXGBE_ESDP_SDP6; 67 dir_sck = IXGBE_ESDP_SDP7_DIR; 68 dir_sdi = IXGBE_ESDP_SDP0_DIR; 69 dir_sdo = IXGBE_ESDP_SDP6_DIR; 70 break; 71 case ixgbe_mac_X540: 72 sck = IXGBE_ESDP_SDP2; 73 sdi = IXGBE_ESDP_SDP0; 74 sdo = IXGBE_ESDP_SDP1; 75 dir_sck = IXGBE_ESDP_SDP2_DIR; 76 dir_sdi = IXGBE_ESDP_SDP0_DIR; 77 dir_sdo = IXGBE_ESDP_SDP1_DIR; 78 break; 79 case ixgbe_mac_X550: 80 case ixgbe_mac_X550EM_x: 81 case ixgbe_mac_X550EM_a: 82 sck = IXGBE_ESDP_SDP2; 83 sdi = IXGBE_ESDP_SDP0; 84 sdo = IXGBE_ESDP_SDP1; 85 dir_sck = IXGBE_ESDP_SDP2_DIR; 86 dir_sdi = IXGBE_ESDP_SDP0_DIR; 87 dir_sdo = IXGBE_ESDP_SDP1_DIR; 88 break; 89 default: 90 return IXGBE_ERR_DEVICE_NOT_SUPPORTED; 91 } 92 93 /* Set SDP pins direction */ 94 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 95 esdp |= dir_sck; /* SCK as output */ 96 esdp |= dir_sdi; /* SDI as output */ 97 esdp &= ~dir_sdo; /* SDO as input */ 98 esdp |= sck; 99 esdp |= sdi; 100 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 101 IXGBE_WRITE_FLUSH(hw); 102 // TODO: 103 msleep(IXGBE_BYPASS_BB_WAIT); 104 105 /* Generate start condition */ 106 esdp &= ~sdi; 107 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 108 IXGBE_WRITE_FLUSH(hw); 109 msleep(IXGBE_BYPASS_BB_WAIT); 110 111 esdp &= ~sck; 112 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 113 IXGBE_WRITE_FLUSH(hw); 114 msleep(IXGBE_BYPASS_BB_WAIT); 115 116 /* Clock out the new control word and clock in the status */ 117 for (i = 0; i < 32; i++) { 118 if ((cmd >> (31 - i)) & 0x01) { 119 esdp |= sdi; 120 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 121 } else { 122 esdp &= ~sdi; 123 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 124 } 125 IXGBE_WRITE_FLUSH(hw); 126 msleep(IXGBE_BYPASS_BB_WAIT); 127 128 esdp |= sck; 129 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 130 IXGBE_WRITE_FLUSH(hw); 131 msleep(IXGBE_BYPASS_BB_WAIT); 132 133 esdp &= ~sck; 134 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 135 IXGBE_WRITE_FLUSH(hw); 136 msleep(IXGBE_BYPASS_BB_WAIT); 137 138 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 139 if (esdp & sdo) 140 *status = (*status << 1) | 0x01; 141 else 142 *status = (*status << 1) | 0x00; 143 msleep(IXGBE_BYPASS_BB_WAIT); 144 } 145 146 /* stop condition */ 147 esdp |= sck; 148 esdp &= ~sdi; 149 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 150 IXGBE_WRITE_FLUSH(hw); 151 msleep(IXGBE_BYPASS_BB_WAIT); 152 153 esdp |= sdi; 154 IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 155 IXGBE_WRITE_FLUSH(hw); 156 157 /* set the page bits to match the cmd that the status it belongs to */ 158 *status = (*status & 0x3fffffff) | (cmd & 0xc0000000); 159 160 return 0; 161 } 162 163 /** 164 * ixgbe_bypass_valid_rd_generic - Verify valid return from bit-bang. 165 * 166 * If we send a write we can't be sure it took until we can read back 167 * that same register. It can be a problem as some of the feilds may 168 * for valid reasons change between the time wrote the register and 169 * we read it again to verify. So this function check everything we 170 * can check and then assumes it worked. 171 * 172 * @u32 in_reg - The register cmd for the bit-bang read. 173 * @u32 out_reg - The register returned from a bit-bang read. 174 **/ 175 static bool ixgbe_bypass_valid_rd_generic(u32 in_reg, u32 out_reg) 176 { 177 u32 mask; 178 179 /* Page must match for all control pages */ 180 if ((in_reg & BYPASS_PAGE_M) != (out_reg & BYPASS_PAGE_M)) 181 return false; 182 183 switch (in_reg & BYPASS_PAGE_M) { 184 case BYPASS_PAGE_CTL0: 185 /* All the following can't change since the last write 186 * - All the event actions 187 * - The timeout value 188 */ 189 mask = BYPASS_AUX_ON_M | BYPASS_MAIN_ON_M | 190 BYPASS_MAIN_OFF_M | BYPASS_AUX_OFF_M | 191 BYPASS_WDTIMEOUT_M | 192 BYPASS_WDT_VALUE_M; 193 if ((out_reg & mask) != (in_reg & mask)) 194 return false; 195 196 /* 0x0 is never a valid value for bypass status */ 197 if (!(out_reg & BYPASS_STATUS_OFF_M)) 198 return false; 199 break; 200 case BYPASS_PAGE_CTL1: 201 /* All the following can't change since the last write 202 * - time valid bit 203 * - time we last sent 204 */ 205 mask = BYPASS_CTL1_VALID_M | BYPASS_CTL1_TIME_M; 206 if ((out_reg & mask) != (in_reg & mask)) 207 return false; 208 break; 209 case BYPASS_PAGE_CTL2: 210 /* All we can check in this page is control number 211 * which is already done above. 212 */ 213 break; 214 } 215 216 /* We are as sure as we can be return true */ 217 return true; 218 } 219 220 /** 221 * ixgbe_bypass_set_generic - Set a bypass field in the FW CTRL Regiter. 222 * 223 * @hw: pointer to hardware structure 224 * @cmd: The control word we are setting. 225 * @event: The event we are setting in the FW. This also happens to 226 * be the mask for the event we are setting (handy) 227 * @action: The action we set the event to in the FW. This is in a 228 * bit field that happens to be what we want to put in 229 * the event spot (also handy) 230 **/ 231 static s32 ixgbe_bypass_set_generic(struct ixgbe_hw *hw, u32 ctrl, u32 event, 232 u32 action) 233 { 234 u32 by_ctl = 0; 235 u32 cmd, verify; 236 u32 count = 0; 237 238 /* Get current values */ 239 cmd = ctrl; /* just reading only need control number */ 240 if (ixgbe_bypass_rw_generic(hw, cmd, &by_ctl)) 241 return IXGBE_ERR_INVALID_ARGUMENT; 242 243 /* Set to new action */ 244 cmd = (by_ctl & ~event) | BYPASS_WE | action; 245 if (ixgbe_bypass_rw_generic(hw, cmd, &by_ctl)) 246 return IXGBE_ERR_INVALID_ARGUMENT; 247 248 /* Page 0 force a FW eeprom write which is slow so verify */ 249 if ((cmd & BYPASS_PAGE_M) == BYPASS_PAGE_CTL0) { 250 verify = BYPASS_PAGE_CTL0; 251 do { 252 if (count++ > 5) 253 return IXGBE_BYPASS_FW_WRITE_FAILURE; 254 255 if (ixgbe_bypass_rw_generic(hw, verify, &by_ctl)) 256 return IXGBE_ERR_INVALID_ARGUMENT; 257 } while (!ixgbe_bypass_valid_rd_generic(cmd, by_ctl)); 258 } else { 259 /* We have give the FW time for the write to stick */ 260 msleep(100); 261 } 262 263 return 0; 264 } 265 266 /** 267 * ixgbe_bypass_rd_eep_generic - Read the bypass FW eeprom address. 268 * 269 * @hw: pointer to hardware structure 270 * @addr: The bypass eeprom address to read. 271 * @value: The 8b of data at the address above. 272 **/ 273 static s32 ixgbe_bypass_rd_eep_generic(struct ixgbe_hw *hw, u32 addr, u8 *value) 274 { 275 u32 cmd; 276 u32 status; 277 278 279 /* send the request */ 280 cmd = BYPASS_PAGE_CTL2 | BYPASS_WE; 281 cmd |= (addr << BYPASS_CTL2_OFFSET_SHIFT) & BYPASS_CTL2_OFFSET_M; 282 if (ixgbe_bypass_rw_generic(hw, cmd, &status)) 283 return IXGBE_ERR_INVALID_ARGUMENT; 284 285 /* We have give the FW time for the write to stick */ 286 msleep(100); 287 288 /* now read the results */ 289 cmd &= ~BYPASS_WE; 290 if (ixgbe_bypass_rw_generic(hw, cmd, &status)) 291 return IXGBE_ERR_INVALID_ARGUMENT; 292 293 *value = status & BYPASS_CTL2_DATA_M; 294 295 return 0; 296 } 297 298 #endif /* RTE_LIBRTE_IXGBE_BYPASS */ 299 300 #endif /* _IXGBE_BYPASS_API_H_ */ 301