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 */