1 /* 2 * Copyright 2007-2013 Solarflare Communications Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include "efsys.h" 27 #include "efx.h" 28 #include "efx_types.h" 29 #include "efx_regs.h" 30 #include "efx_impl.h" 31 32 #if EFSYS_OPT_FALCON 33 34 /* Commands common to all known devices */ 35 36 #define SPI_CMD_WRSR 0x01 /* write status register */ 37 #define SPI_CMD_WRITE 0x02 /* Write data to memory array */ 38 #define SPI_CMD_READ 0x03 /* Read data from memory array */ 39 #define SPI_CMD_WRDI 0x04 /* reset write enable latch */ 40 #define SPI_CMD_RDSR 0x05 /* read status register */ 41 #define SPI_CMD_WREN 0x06 /* set write enable latch */ 42 43 #define SPI_CMD_SECE 0x52 /* erase one sector */ 44 45 #define SPI_STATUS_WPEN_LBN 7 46 #define SPI_STATUS_WPEN_WIDTH 1 47 #define SPI_STATUS_BP2_LBN 4 48 #define SPI_STATUS_BP2_WIDTH 1 49 #define SPI_STATUS_BP1_LBN 3 50 #define SPI_STATUS_BP1_WIDTH 1 51 #define SPI_STATUS_BP0_LBN 2 52 #define SPI_STATUS_BP0_WIDTH 1 53 #define SPI_STATUS_WEN_LBN 1 54 #define SPI_STATUS_WEN_WIDTH 1 55 #define SPI_STATUS_NRDY_LBN 0 56 #define SPI_STATUS_NRDY_WIDTH 1 57 58 static __checkReturn int 59 falcon_spi_wait( 60 __in efx_nic_t *enp) 61 { 62 unsigned int count; 63 int rc; 64 65 count = 0; 66 do { 67 efx_oword_t oword; 68 69 EFSYS_PROBE1(wait, unsigned int, count); 70 71 EFX_BAR_READO(enp, FR_AB_EE_SPI_HCMD_REG, &oword); 72 73 if (EFX_OWORD_FIELD(oword, FRF_AB_EE_SPI_HCMD_CMD_EN) == 0) 74 goto done; 75 76 /* Spin for 10 us */ 77 EFSYS_SPIN(10); 78 } while (++count < 10000); 79 80 rc = ETIMEDOUT; 81 goto fail1; 82 83 done: 84 return (0); 85 86 fail1: 87 EFSYS_PROBE1(fail1, int, rc); 88 89 return (rc); 90 } 91 92 #define FALCON_SPI_COPY(_dst, _src, _size) \ 93 do { \ 94 unsigned int index; \ 95 \ 96 for (index = 0; index < (unsigned int)(_size); index++) \ 97 *((uint8_t *)(_dst) + index) = \ 98 *((uint8_t *)(_src) + index); \ 99 \ 100 _NOTE(CONSTANTCONDITION) \ 101 } while (B_FALSE) 102 103 static __checkReturn int 104 falcon_spi_cmd( 105 __in efx_nic_t *enp, 106 __in uint32_t sf_sel, 107 __in uint32_t adbcnt, 108 __in uint32_t cmd, 109 __in uint32_t addr, 110 __in boolean_t munge, 111 __drv_when(cmd == SPI_CMD_WRSR || cmd == SPI_CMD_WRITE, 112 __drv_in(__byte_readableTo(dabcnt))) 113 __drv_when(cmd == SPI_CMD_RDSR || cmd == SPI_CMD_READ, 114 __drv_out(__byte_readableTo(dabcnt))) 115 caddr_t base, 116 __in uint32_t dabcnt) 117 { 118 uint32_t enc; 119 efx_oword_t oword; 120 int rc; 121 122 EFSYS_ASSERT3U(dabcnt, <=, sizeof (efx_oword_t)); 123 124 /* Wait for the SPI to become available */ 125 if ((rc = falcon_spi_wait(enp)) != 0) 126 goto fail1; 127 128 /* Program the data register */ 129 if (cmd == SPI_CMD_WRSR || cmd == SPI_CMD_WRITE) { 130 EFSYS_ASSERT(base != NULL); 131 EFSYS_ASSERT(dabcnt != 0); 132 EFX_ZERO_OWORD(oword); 133 FALCON_SPI_COPY(&oword, base, dabcnt); 134 EFX_BAR_WRITEO(enp, FR_AB_EE_SPI_HDATA_REG, &oword); 135 } 136 137 /* Program the address register */ 138 if (cmd == SPI_CMD_READ || cmd == SPI_CMD_WRITE || 139 cmd == SPI_CMD_SECE) { 140 EFX_POPULATE_OWORD_1(oword, FRF_AB_EE_SPI_HADR_ADR, addr); 141 EFX_BAR_WRITEO(enp, FR_AB_EE_SPI_HADR_REG, &oword); 142 143 enc = (munge) ? (cmd | ((addr >> 8) << 3)) : cmd; 144 } else { 145 enc = cmd; 146 } 147 148 /* Issue command */ 149 EFX_POPULATE_OWORD_6(oword, FRF_AB_EE_SPI_HCMD_CMD_EN, 1, 150 FRF_AB_EE_SPI_HCMD_SF_SEL, sf_sel, 151 FRF_AB_EE_SPI_HCMD_DABCNT, dabcnt, 152 FRF_AB_EE_SPI_HCMD_DUBCNT, 0, 153 FRF_AB_EE_SPI_HCMD_ADBCNT, adbcnt, 154 FRF_AB_EE_SPI_HCMD_ENC, enc); 155 156 EFX_SET_OWORD_FIELD(oword, 157 FRF_AB_EE_SPI_HCMD_READ, 158 (cmd == SPI_CMD_RDSR || cmd == SPI_CMD_READ) ? 1 : 0); 159 160 EFX_BAR_WRITEO(enp, FR_AB_EE_SPI_HCMD_REG, &oword); 161 162 /* Wait for read to complete */ 163 if ((rc = falcon_spi_wait(enp)) != 0) 164 goto fail2; 165 166 /* Read the data register */ 167 if (cmd == SPI_CMD_RDSR || cmd == SPI_CMD_READ) { 168 EFX_BAR_READO(enp, FR_AB_EE_SPI_HDATA_REG, &oword); 169 EFSYS_ASSERT(base != NULL); 170 FALCON_SPI_COPY(base, &oword, dabcnt); 171 } 172 173 return (0); 174 175 fail2: 176 EFSYS_PROBE(fail2); 177 fail1: 178 EFSYS_PROBE1(fail1, int, rc); 179 180 return (rc); 181 } 182 183 static __checkReturn int 184 falcon_spi_dev_wait( 185 __in efx_nic_t *enp, 186 __in falcon_spi_dev_t *fsdp, 187 __in unsigned int us, 188 __in unsigned int n) 189 { 190 unsigned int count; 191 int rc; 192 193 count = 0; 194 do { 195 efx_byte_t byte; 196 197 EFSYS_PROBE1(wait, unsigned int, count); 198 199 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel, 200 fsdp->fsd_adbcnt, SPI_CMD_RDSR, 0, fsdp->fsd_munge, 201 (caddr_t)&byte, sizeof (efx_byte_t))) != 0) 202 goto fail1; 203 204 if (EFX_BYTE_FIELD(byte, SPI_STATUS_NRDY) == 0) 205 goto done; 206 207 EFSYS_SPIN(us); 208 } while (++count < n); 209 210 rc = ETIMEDOUT; 211 goto fail2; 212 213 done: 214 return (0); 215 216 fail2: 217 EFSYS_PROBE(fail2); 218 fail1: 219 EFSYS_PROBE1(fail1, int, rc); 220 221 return (rc); 222 } 223 224 __checkReturn int 225 falcon_spi_dev_read( 226 __in efx_nic_t *enp, 227 __in falcon_spi_type_t type, 228 __in uint32_t addr, 229 __out_bcount(size) caddr_t base, 230 __in size_t size) 231 { 232 falcon_spi_dev_t *fsdp = &(enp->en_u.falcon.enu_fsd[type]); 233 uint32_t end = addr + size; 234 int state; 235 int rc; 236 237 EFSYS_ASSERT3U(type, <, FALCON_SPI_NTYPES); 238 239 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON); 240 241 if (fsdp == NULL) { 242 rc = ENODEV; 243 goto fail1; 244 } 245 246 EFSYS_LOCK(enp->en_eslp, state); 247 248 while (addr != end) { 249 uint32_t dabcnt = MIN(end - addr, sizeof (efx_oword_t)); 250 251 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel, 252 fsdp->fsd_adbcnt, SPI_CMD_READ, addr, fsdp->fsd_munge, 253 base, dabcnt)) != 0) 254 goto fail2; 255 256 EFSYS_ASSERT3U(addr, <, end); 257 addr += dabcnt; 258 base += dabcnt; 259 } 260 261 EFSYS_UNLOCK(enp->en_eslp, state); 262 return (0); 263 264 fail2: 265 EFSYS_PROBE(fail2); 266 267 EFSYS_UNLOCK(enp->en_eslp, state); 268 269 fail1: 270 EFSYS_PROBE1(fail1, int, rc); 271 272 return (rc); 273 } 274 275 __checkReturn int 276 falcon_spi_dev_write( 277 __in efx_nic_t *enp, 278 __in falcon_spi_type_t type, 279 __in uint32_t addr, 280 __in_bcount(size) caddr_t base, 281 __in size_t size) 282 { 283 falcon_spi_dev_t *fsdp = &(enp->en_u.falcon.enu_fsd[type]); 284 uint32_t end = addr + size; 285 int state; 286 int rc; 287 288 EFSYS_ASSERT3U(type, <, FALCON_SPI_NTYPES); 289 290 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON); 291 292 if (fsdp == NULL) { 293 rc = ENODEV; 294 goto fail1; 295 } 296 297 EFSYS_LOCK(enp->en_eslp, state); 298 299 while (addr != end) { 300 efx_oword_t oword; 301 uint32_t dabcnt; 302 unsigned int index; 303 304 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel, 305 fsdp->fsd_adbcnt, SPI_CMD_WREN, 0, fsdp->fsd_munge, 306 NULL, 0)) != 0) 307 goto fail2; 308 309 dabcnt = MIN(end - addr, fsdp->fsd_write_size - 310 (addr & (fsdp->fsd_write_size - 1))); 311 dabcnt = MIN(dabcnt, sizeof (efx_oword_t)); 312 313 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel, 314 fsdp->fsd_adbcnt, SPI_CMD_WRITE, addr, 315 fsdp->fsd_munge, base, dabcnt)) != 0) 316 goto fail3; 317 318 if ((rc = falcon_spi_dev_wait(enp, fsdp, 1000, 20)) != 0) 319 goto fail4; 320 321 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel, 322 fsdp->fsd_adbcnt, SPI_CMD_READ, addr, 323 fsdp->fsd_munge, (caddr_t)&oword, dabcnt)) != 0) 324 goto fail5; 325 326 for (index = 0; index < dabcnt; index++) { 327 if (oword.eo_u8[index] != *(uint8_t *)(base + index)) { 328 rc = EIO; 329 goto fail6; 330 } 331 } 332 333 EFSYS_ASSERT3U(addr, <, end); 334 addr += dabcnt; 335 base += dabcnt; 336 } 337 338 EFSYS_UNLOCK(enp->en_eslp, state); 339 return (0); 340 341 fail6: 342 EFSYS_PROBE(fail6); 343 fail5: 344 EFSYS_PROBE(fail5); 345 fail4: 346 EFSYS_PROBE(fail4); 347 fail3: 348 EFSYS_PROBE(fail3); 349 fail2: 350 EFSYS_PROBE(fail2); 351 352 EFSYS_UNLOCK(enp->en_eslp, state); 353 fail1: 354 EFSYS_PROBE1(fail1, int, rc); 355 356 return (rc); 357 } 358 359 __checkReturn int 360 falcon_spi_dev_erase( 361 __in efx_nic_t *enp, 362 __in falcon_spi_type_t type, 363 __in uint32_t addr, 364 __in size_t size) 365 { 366 falcon_spi_dev_t *fsdp = &(enp->en_u.falcon.enu_fsd[type]); 367 uint32_t end = addr + size; 368 int state; 369 int rc; 370 371 EFSYS_ASSERT3U(type, <, FALCON_SPI_NTYPES); 372 373 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON); 374 375 if (fsdp == NULL) { 376 rc = ENODEV; 377 goto fail1; 378 } 379 380 if (fsdp->fsd_erase_cmd == 0) { 381 rc = ENOTSUP; 382 goto fail2; 383 } 384 385 if (!IS_P2ALIGNED(addr, fsdp->fsd_erase_size) || 386 !IS_P2ALIGNED(size, fsdp->fsd_erase_size)) { 387 rc = EINVAL; 388 goto fail3; 389 } 390 391 EFSYS_LOCK(enp->en_eslp, state); 392 393 while (addr != end) { 394 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel, 395 fsdp->fsd_adbcnt, SPI_CMD_WREN, 0, fsdp->fsd_munge, 396 NULL, 0)) != 0) 397 goto fail4; 398 399 if ((rc = falcon_spi_cmd(enp, fsdp->fsd_sf_sel, 400 fsdp->fsd_adbcnt, fsdp->fsd_erase_cmd, addr, 401 fsdp->fsd_munge, NULL, 0)) != 0) 402 goto fail5; 403 404 if ((rc = falcon_spi_dev_wait(enp, fsdp, 40000, 100)) != 0) 405 goto fail6; 406 407 EFSYS_ASSERT3U(addr, <, end); 408 addr += fsdp->fsd_erase_size; 409 } 410 411 EFSYS_UNLOCK(enp->en_eslp, state); 412 return (0); 413 414 fail6: 415 EFSYS_PROBE(fail6); 416 fail5: 417 EFSYS_PROBE(fail5); 418 fail4: 419 EFSYS_PROBE(fail4); 420 421 EFSYS_UNLOCK(enp->en_eslp, state); 422 423 fail3: 424 EFSYS_PROBE(fail3); 425 fail2: 426 EFSYS_PROBE(fail2); 427 fail1: 428 EFSYS_PROBE1(fail1, int, rc); 429 430 return (rc); 431 } 432 433 #endif /* EFSYS_OPT_FALCON */