1*e3ee7b7dSSheetal Tigadoli /* 2*e3ee7b7dSSheetal Tigadoli * Copyright (c) 2017 - 2020, Broadcom 3*e3ee7b7dSSheetal Tigadoli * 4*e3ee7b7dSSheetal Tigadoli * SPDX-License-Identifier: BSD-3-Clause 5*e3ee7b7dSSheetal Tigadoli */ 6*e3ee7b7dSSheetal Tigadoli 7*e3ee7b7dSSheetal Tigadoli #include <string.h> 8*e3ee7b7dSSheetal Tigadoli 9*e3ee7b7dSSheetal Tigadoli #include <common/debug.h> 10*e3ee7b7dSSheetal Tigadoli #include <drivers/delay_timer.h> 11*e3ee7b7dSSheetal Tigadoli #include <endian.h> 12*e3ee7b7dSSheetal Tigadoli #include <lib/mmio.h> 13*e3ee7b7dSSheetal Tigadoli 14*e3ee7b7dSSheetal Tigadoli #include <platform_def.h> 15*e3ee7b7dSSheetal Tigadoli #include <spi.h> 16*e3ee7b7dSSheetal Tigadoli 17*e3ee7b7dSSheetal Tigadoli #include "iproc_qspi.h" 18*e3ee7b7dSSheetal Tigadoli 19*e3ee7b7dSSheetal Tigadoli struct bcmspi_priv spi_cfg; 20*e3ee7b7dSSheetal Tigadoli 21*e3ee7b7dSSheetal Tigadoli /* Redefined by platform to force appropriate information */ 22*e3ee7b7dSSheetal Tigadoli #pragma weak plat_spi_init 23*e3ee7b7dSSheetal Tigadoli int plat_spi_init(uint32_t *max_hz) 24*e3ee7b7dSSheetal Tigadoli { 25*e3ee7b7dSSheetal Tigadoli return 0; 26*e3ee7b7dSSheetal Tigadoli } 27*e3ee7b7dSSheetal Tigadoli 28*e3ee7b7dSSheetal Tigadoli /* Initialize & setup iproc qspi controller */ 29*e3ee7b7dSSheetal Tigadoli int iproc_qspi_setup(uint32_t bus, uint32_t cs, uint32_t max_hz, uint32_t mode) 30*e3ee7b7dSSheetal Tigadoli { 31*e3ee7b7dSSheetal Tigadoli struct bcmspi_priv *priv = NULL; 32*e3ee7b7dSSheetal Tigadoli uint32_t spbr; 33*e3ee7b7dSSheetal Tigadoli 34*e3ee7b7dSSheetal Tigadoli priv = &spi_cfg; 35*e3ee7b7dSSheetal Tigadoli priv->spi_mode = mode; 36*e3ee7b7dSSheetal Tigadoli priv->state = QSPI_STATE_DISABLED; 37*e3ee7b7dSSheetal Tigadoli priv->bspi_hw = QSPI_BSPI_MODE_REG_BASE; 38*e3ee7b7dSSheetal Tigadoli priv->mspi_hw = QSPI_MSPI_MODE_REG_BASE; 39*e3ee7b7dSSheetal Tigadoli 40*e3ee7b7dSSheetal Tigadoli /* Initialize clock and platform specific */ 41*e3ee7b7dSSheetal Tigadoli if (plat_spi_init(&max_hz) != 0) 42*e3ee7b7dSSheetal Tigadoli return -1; 43*e3ee7b7dSSheetal Tigadoli 44*e3ee7b7dSSheetal Tigadoli priv->max_hz = max_hz; 45*e3ee7b7dSSheetal Tigadoli 46*e3ee7b7dSSheetal Tigadoli /* MSPI: Basic hardware initialization */ 47*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_SPCR1_LSB_REG, 0); 48*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_SPCR1_MSB_REG, 0); 49*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_NEWQP_REG, 0); 50*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_ENDQP_REG, 0); 51*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_SPCR2_REG, 0); 52*e3ee7b7dSSheetal Tigadoli 53*e3ee7b7dSSheetal Tigadoli /* MSPI: SCK configuration */ 54*e3ee7b7dSSheetal Tigadoli spbr = (QSPI_AXI_CLK - 1) / (2 * priv->max_hz) + 1; 55*e3ee7b7dSSheetal Tigadoli spbr = MIN(spbr, SPBR_DIV_MAX); 56*e3ee7b7dSSheetal Tigadoli spbr = MAX(spbr, SPBR_DIV_MIN); 57*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_SPCR0_LSB_REG, spbr); 58*e3ee7b7dSSheetal Tigadoli 59*e3ee7b7dSSheetal Tigadoli /* MSPI: Mode configuration (8 bits by default) */ 60*e3ee7b7dSSheetal Tigadoli priv->mspi_16bit = 0; 61*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_SPCR0_MSB_REG, 62*e3ee7b7dSSheetal Tigadoli BIT(MSPI_SPCR0_MSB_REG_MSTR_SHIFT) | /* Master */ 63*e3ee7b7dSSheetal Tigadoli MSPI_SPCR0_MSB_REG_16_BITS_PER_WD_SHIFT | /* 16 bits per word */ 64*e3ee7b7dSSheetal Tigadoli (priv->spi_mode & MSPI_SPCR0_MSB_REG_MODE_MASK)); /* mode: CPOL / CPHA */ 65*e3ee7b7dSSheetal Tigadoli 66*e3ee7b7dSSheetal Tigadoli /* Display bus info */ 67*e3ee7b7dSSheetal Tigadoli VERBOSE("SPI: SPCR0_LSB: 0x%x\n", 68*e3ee7b7dSSheetal Tigadoli mmio_read_32(priv->mspi_hw + MSPI_SPCR0_LSB_REG)); 69*e3ee7b7dSSheetal Tigadoli VERBOSE("SPI: SPCR0_MSB: 0x%x\n", 70*e3ee7b7dSSheetal Tigadoli mmio_read_32(priv->mspi_hw + MSPI_SPCR0_MSB_REG)); 71*e3ee7b7dSSheetal Tigadoli VERBOSE("SPI: SPCR1_LSB: 0x%x\n", 72*e3ee7b7dSSheetal Tigadoli mmio_read_32(priv->mspi_hw + MSPI_SPCR1_LSB_REG)); 73*e3ee7b7dSSheetal Tigadoli VERBOSE("SPI: SPCR1_MSB: 0x%x\n", 74*e3ee7b7dSSheetal Tigadoli mmio_read_32(priv->mspi_hw + MSPI_SPCR1_MSB_REG)); 75*e3ee7b7dSSheetal Tigadoli VERBOSE("SPI: SPCR2: 0x%x\n", 76*e3ee7b7dSSheetal Tigadoli mmio_read_32(priv->mspi_hw + MSPI_SPCR2_REG)); 77*e3ee7b7dSSheetal Tigadoli VERBOSE("SPI: CLK: %d\n", priv->max_hz); 78*e3ee7b7dSSheetal Tigadoli 79*e3ee7b7dSSheetal Tigadoli return 0; 80*e3ee7b7dSSheetal Tigadoli } 81*e3ee7b7dSSheetal Tigadoli 82*e3ee7b7dSSheetal Tigadoli void bcmspi_enable_bspi(struct bcmspi_priv *priv) 83*e3ee7b7dSSheetal Tigadoli { 84*e3ee7b7dSSheetal Tigadoli if (priv->state != QSPI_STATE_BSPI) { 85*e3ee7b7dSSheetal Tigadoli /* Switch to BSPI */ 86*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->bspi_hw + BSPI_MAST_N_BOOT_CTRL_REG, 0); 87*e3ee7b7dSSheetal Tigadoli 88*e3ee7b7dSSheetal Tigadoli priv->state = QSPI_STATE_BSPI; 89*e3ee7b7dSSheetal Tigadoli } 90*e3ee7b7dSSheetal Tigadoli } 91*e3ee7b7dSSheetal Tigadoli 92*e3ee7b7dSSheetal Tigadoli static int bcmspi_disable_bspi(struct bcmspi_priv *priv) 93*e3ee7b7dSSheetal Tigadoli { 94*e3ee7b7dSSheetal Tigadoli uint32_t retry; 95*e3ee7b7dSSheetal Tigadoli 96*e3ee7b7dSSheetal Tigadoli if (priv->state == QSPI_STATE_MSPI) 97*e3ee7b7dSSheetal Tigadoli return 0; 98*e3ee7b7dSSheetal Tigadoli 99*e3ee7b7dSSheetal Tigadoli /* Switch to MSPI if not yet */ 100*e3ee7b7dSSheetal Tigadoli if ((mmio_read_32(priv->bspi_hw + BSPI_MAST_N_BOOT_CTRL_REG) & 101*e3ee7b7dSSheetal Tigadoli MSPI_CTRL_MASK) == 0) { 102*e3ee7b7dSSheetal Tigadoli retry = QSPI_RETRY_COUNT_US_MAX; 103*e3ee7b7dSSheetal Tigadoli do { 104*e3ee7b7dSSheetal Tigadoli if ((mmio_read_32( 105*e3ee7b7dSSheetal Tigadoli priv->bspi_hw + BSPI_BUSY_STATUS_REG) & 106*e3ee7b7dSSheetal Tigadoli BSPI_BUSY_MASK) == 0) { 107*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->bspi_hw + 108*e3ee7b7dSSheetal Tigadoli BSPI_MAST_N_BOOT_CTRL_REG, 109*e3ee7b7dSSheetal Tigadoli MSPI_CTRL_MASK); 110*e3ee7b7dSSheetal Tigadoli udelay(1); 111*e3ee7b7dSSheetal Tigadoli break; 112*e3ee7b7dSSheetal Tigadoli } 113*e3ee7b7dSSheetal Tigadoli udelay(1); 114*e3ee7b7dSSheetal Tigadoli } while (retry--); 115*e3ee7b7dSSheetal Tigadoli 116*e3ee7b7dSSheetal Tigadoli if ((mmio_read_32(priv->bspi_hw + BSPI_MAST_N_BOOT_CTRL_REG) & 117*e3ee7b7dSSheetal Tigadoli MSPI_CTRL_MASK) != MSPI_CTRL_MASK) { 118*e3ee7b7dSSheetal Tigadoli ERROR("QSPI: Switching to QSPI error.\n"); 119*e3ee7b7dSSheetal Tigadoli return -1; 120*e3ee7b7dSSheetal Tigadoli } 121*e3ee7b7dSSheetal Tigadoli } 122*e3ee7b7dSSheetal Tigadoli 123*e3ee7b7dSSheetal Tigadoli /* Update state */ 124*e3ee7b7dSSheetal Tigadoli priv->state = QSPI_STATE_MSPI; 125*e3ee7b7dSSheetal Tigadoli 126*e3ee7b7dSSheetal Tigadoli return 0; 127*e3ee7b7dSSheetal Tigadoli } 128*e3ee7b7dSSheetal Tigadoli 129*e3ee7b7dSSheetal Tigadoli int iproc_qspi_claim_bus(void) 130*e3ee7b7dSSheetal Tigadoli { 131*e3ee7b7dSSheetal Tigadoli struct bcmspi_priv *priv = &spi_cfg; 132*e3ee7b7dSSheetal Tigadoli 133*e3ee7b7dSSheetal Tigadoli /* Switch to MSPI by default */ 134*e3ee7b7dSSheetal Tigadoli if (bcmspi_disable_bspi(priv) != 0) 135*e3ee7b7dSSheetal Tigadoli return -1; 136*e3ee7b7dSSheetal Tigadoli 137*e3ee7b7dSSheetal Tigadoli return 0; 138*e3ee7b7dSSheetal Tigadoli } 139*e3ee7b7dSSheetal Tigadoli 140*e3ee7b7dSSheetal Tigadoli void iproc_qspi_release_bus(void) 141*e3ee7b7dSSheetal Tigadoli { 142*e3ee7b7dSSheetal Tigadoli struct bcmspi_priv *priv = &spi_cfg; 143*e3ee7b7dSSheetal Tigadoli 144*e3ee7b7dSSheetal Tigadoli /* Switch to BSPI by default */ 145*e3ee7b7dSSheetal Tigadoli bcmspi_enable_bspi(priv); 146*e3ee7b7dSSheetal Tigadoli } 147*e3ee7b7dSSheetal Tigadoli 148*e3ee7b7dSSheetal Tigadoli static int mspi_xfer(struct bcmspi_priv *priv, uint32_t bytes, 149*e3ee7b7dSSheetal Tigadoli const uint8_t *tx, uint8_t *rx, uint32_t flag) 150*e3ee7b7dSSheetal Tigadoli { 151*e3ee7b7dSSheetal Tigadoli uint32_t retry; 152*e3ee7b7dSSheetal Tigadoli uint32_t mode = CDRAM_PCS0; 153*e3ee7b7dSSheetal Tigadoli 154*e3ee7b7dSSheetal Tigadoli if (flag & SPI_XFER_QUAD) { 155*e3ee7b7dSSheetal Tigadoli mode |= CDRAM_QUAD_MODE; 156*e3ee7b7dSSheetal Tigadoli VERBOSE("SPI: QUAD mode\n"); 157*e3ee7b7dSSheetal Tigadoli 158*e3ee7b7dSSheetal Tigadoli if (!tx) { 159*e3ee7b7dSSheetal Tigadoli VERBOSE("SPI: 4 lane input\n"); 160*e3ee7b7dSSheetal Tigadoli mode |= CDRAM_RBIT_INPUT; 161*e3ee7b7dSSheetal Tigadoli } 162*e3ee7b7dSSheetal Tigadoli } 163*e3ee7b7dSSheetal Tigadoli 164*e3ee7b7dSSheetal Tigadoli /* Use 8-bit queue for odd-bytes transfer */ 165*e3ee7b7dSSheetal Tigadoli if (bytes & 1) 166*e3ee7b7dSSheetal Tigadoli priv->mspi_16bit = 0; 167*e3ee7b7dSSheetal Tigadoli else { 168*e3ee7b7dSSheetal Tigadoli priv->mspi_16bit = 1; 169*e3ee7b7dSSheetal Tigadoli mode |= CDRAM_BITS_EN; 170*e3ee7b7dSSheetal Tigadoli } 171*e3ee7b7dSSheetal Tigadoli 172*e3ee7b7dSSheetal Tigadoli while (bytes) { 173*e3ee7b7dSSheetal Tigadoli uint32_t chunk; 174*e3ee7b7dSSheetal Tigadoli uint32_t queues; 175*e3ee7b7dSSheetal Tigadoli uint32_t i; 176*e3ee7b7dSSheetal Tigadoli 177*e3ee7b7dSSheetal Tigadoli /* Separate code for 16bit and 8bit transfers for performance */ 178*e3ee7b7dSSheetal Tigadoli if (priv->mspi_16bit) { 179*e3ee7b7dSSheetal Tigadoli VERBOSE("SPI: 16 bits xfer\n"); 180*e3ee7b7dSSheetal Tigadoli /* Determine how many bytes to process this time */ 181*e3ee7b7dSSheetal Tigadoli chunk = MIN(bytes, NUM_CDRAM_BYTES * 2); 182*e3ee7b7dSSheetal Tigadoli queues = (chunk - 1) / 2 + 1; 183*e3ee7b7dSSheetal Tigadoli bytes -= chunk; 184*e3ee7b7dSSheetal Tigadoli 185*e3ee7b7dSSheetal Tigadoli /* Fill CDRAMs */ 186*e3ee7b7dSSheetal Tigadoli for (i = 0; i < queues; i++) 187*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_CDRAM_REG + 188*e3ee7b7dSSheetal Tigadoli (i << 2), mode | CDRAM_CONT); 189*e3ee7b7dSSheetal Tigadoli 190*e3ee7b7dSSheetal Tigadoli /* Fill TXRAMs */ 191*e3ee7b7dSSheetal Tigadoli for (i = 0; i < chunk; i++) 192*e3ee7b7dSSheetal Tigadoli if (tx) 193*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + 194*e3ee7b7dSSheetal Tigadoli MSPI_TXRAM_REG + 195*e3ee7b7dSSheetal Tigadoli (i << 2), tx[i]); 196*e3ee7b7dSSheetal Tigadoli } else { 197*e3ee7b7dSSheetal Tigadoli VERBOSE("SPI: 8 bits xfer\n"); 198*e3ee7b7dSSheetal Tigadoli /* Determine how many bytes to process this time */ 199*e3ee7b7dSSheetal Tigadoli chunk = MIN(bytes, NUM_CDRAM_BYTES); 200*e3ee7b7dSSheetal Tigadoli queues = chunk; 201*e3ee7b7dSSheetal Tigadoli bytes -= chunk; 202*e3ee7b7dSSheetal Tigadoli 203*e3ee7b7dSSheetal Tigadoli /* Fill CDRAMs and TXRAMS */ 204*e3ee7b7dSSheetal Tigadoli for (i = 0; i < chunk; i++) { 205*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_CDRAM_REG + 206*e3ee7b7dSSheetal Tigadoli (i << 2), mode | CDRAM_CONT); 207*e3ee7b7dSSheetal Tigadoli if (tx) 208*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + 209*e3ee7b7dSSheetal Tigadoli MSPI_TXRAM_REG + 210*e3ee7b7dSSheetal Tigadoli (i << 3), tx[i]); 211*e3ee7b7dSSheetal Tigadoli } 212*e3ee7b7dSSheetal Tigadoli } 213*e3ee7b7dSSheetal Tigadoli 214*e3ee7b7dSSheetal Tigadoli /* Advance pointers */ 215*e3ee7b7dSSheetal Tigadoli if (tx) 216*e3ee7b7dSSheetal Tigadoli tx += chunk; 217*e3ee7b7dSSheetal Tigadoli 218*e3ee7b7dSSheetal Tigadoli /* Setup queue pointers */ 219*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_NEWQP_REG, 0); 220*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_ENDQP_REG, queues - 1); 221*e3ee7b7dSSheetal Tigadoli 222*e3ee7b7dSSheetal Tigadoli /* Remove CONT on the last byte command */ 223*e3ee7b7dSSheetal Tigadoli if (bytes == 0 && (flag & SPI_XFER_END)) 224*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_CDRAM_REG + 225*e3ee7b7dSSheetal Tigadoli ((queues - 1) << 2), mode); 226*e3ee7b7dSSheetal Tigadoli 227*e3ee7b7dSSheetal Tigadoli /* Kick off */ 228*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_STATUS_REG, 0); 229*e3ee7b7dSSheetal Tigadoli if (bytes == 0 && (flag & SPI_XFER_END)) 230*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_SPCR2_REG, MSPI_SPE); 231*e3ee7b7dSSheetal Tigadoli else 232*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_SPCR2_REG, 233*e3ee7b7dSSheetal Tigadoli MSPI_SPE | MSPI_CONT_AFTER_CMD); 234*e3ee7b7dSSheetal Tigadoli 235*e3ee7b7dSSheetal Tigadoli /* Wait for completion */ 236*e3ee7b7dSSheetal Tigadoli retry = QSPI_RETRY_COUNT_US_MAX; 237*e3ee7b7dSSheetal Tigadoli do { 238*e3ee7b7dSSheetal Tigadoli if (mmio_read_32(priv->mspi_hw + MSPI_STATUS_REG) & 239*e3ee7b7dSSheetal Tigadoli MSPI_CMD_COMPLETE_MASK) 240*e3ee7b7dSSheetal Tigadoli break; 241*e3ee7b7dSSheetal Tigadoli udelay(1); 242*e3ee7b7dSSheetal Tigadoli } while (retry--); 243*e3ee7b7dSSheetal Tigadoli 244*e3ee7b7dSSheetal Tigadoli if ((mmio_read_32(priv->mspi_hw + MSPI_STATUS_REG) & 245*e3ee7b7dSSheetal Tigadoli MSPI_CMD_COMPLETE_MASK) == 0) { 246*e3ee7b7dSSheetal Tigadoli ERROR("SPI: Completion timeout.\n"); 247*e3ee7b7dSSheetal Tigadoli return -1; 248*e3ee7b7dSSheetal Tigadoli } 249*e3ee7b7dSSheetal Tigadoli 250*e3ee7b7dSSheetal Tigadoli /* Read data out */ 251*e3ee7b7dSSheetal Tigadoli if (rx) { 252*e3ee7b7dSSheetal Tigadoli if (priv->mspi_16bit) { 253*e3ee7b7dSSheetal Tigadoli for (i = 0; i < chunk; i++) { 254*e3ee7b7dSSheetal Tigadoli rx[i] = mmio_read_32(priv->mspi_hw + 255*e3ee7b7dSSheetal Tigadoli MSPI_RXRAM_REG + 256*e3ee7b7dSSheetal Tigadoli (i << 2)) 257*e3ee7b7dSSheetal Tigadoli & 0xff; 258*e3ee7b7dSSheetal Tigadoli } 259*e3ee7b7dSSheetal Tigadoli } else { 260*e3ee7b7dSSheetal Tigadoli for (i = 0; i < chunk; i++) { 261*e3ee7b7dSSheetal Tigadoli rx[i] = mmio_read_32(priv->mspi_hw + 262*e3ee7b7dSSheetal Tigadoli MSPI_RXRAM_REG + 263*e3ee7b7dSSheetal Tigadoli (((i << 1) + 1) << 2)) 264*e3ee7b7dSSheetal Tigadoli & 0xff; 265*e3ee7b7dSSheetal Tigadoli } 266*e3ee7b7dSSheetal Tigadoli } 267*e3ee7b7dSSheetal Tigadoli rx += chunk; 268*e3ee7b7dSSheetal Tigadoli } 269*e3ee7b7dSSheetal Tigadoli } 270*e3ee7b7dSSheetal Tigadoli 271*e3ee7b7dSSheetal Tigadoli return 0; 272*e3ee7b7dSSheetal Tigadoli } 273*e3ee7b7dSSheetal Tigadoli 274*e3ee7b7dSSheetal Tigadoli int iproc_qspi_xfer(uint32_t bitlen, 275*e3ee7b7dSSheetal Tigadoli const void *dout, void *din, unsigned long flags) 276*e3ee7b7dSSheetal Tigadoli { 277*e3ee7b7dSSheetal Tigadoli struct bcmspi_priv *priv; 278*e3ee7b7dSSheetal Tigadoli const uint8_t *tx = dout; 279*e3ee7b7dSSheetal Tigadoli uint8_t *rx = din; 280*e3ee7b7dSSheetal Tigadoli uint32_t bytes = bitlen / 8; 281*e3ee7b7dSSheetal Tigadoli int ret = 0; 282*e3ee7b7dSSheetal Tigadoli 283*e3ee7b7dSSheetal Tigadoli priv = &spi_cfg; 284*e3ee7b7dSSheetal Tigadoli 285*e3ee7b7dSSheetal Tigadoli if (priv->state == QSPI_STATE_DISABLED) { 286*e3ee7b7dSSheetal Tigadoli ERROR("QSPI: state disabled\n"); 287*e3ee7b7dSSheetal Tigadoli return -1; 288*e3ee7b7dSSheetal Tigadoli } 289*e3ee7b7dSSheetal Tigadoli 290*e3ee7b7dSSheetal Tigadoli /* we can only do 8 bit transfers */ 291*e3ee7b7dSSheetal Tigadoli if (bitlen % 8) { 292*e3ee7b7dSSheetal Tigadoli ERROR("QSPI: Only support 8 bit transfers (requested %d)\n", 293*e3ee7b7dSSheetal Tigadoli bitlen); 294*e3ee7b7dSSheetal Tigadoli return -1; 295*e3ee7b7dSSheetal Tigadoli } 296*e3ee7b7dSSheetal Tigadoli 297*e3ee7b7dSSheetal Tigadoli /* MSPI: Enable write lock at the beginning */ 298*e3ee7b7dSSheetal Tigadoli if (flags & SPI_XFER_BEGIN) { 299*e3ee7b7dSSheetal Tigadoli /* Switch to MSPI if not yet */ 300*e3ee7b7dSSheetal Tigadoli if (bcmspi_disable_bspi(priv) != 0) { 301*e3ee7b7dSSheetal Tigadoli ERROR("QSPI: Switch to MSPI failed\n"); 302*e3ee7b7dSSheetal Tigadoli return -1; 303*e3ee7b7dSSheetal Tigadoli } 304*e3ee7b7dSSheetal Tigadoli 305*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_WRITE_LOCK_REG, 1); 306*e3ee7b7dSSheetal Tigadoli } 307*e3ee7b7dSSheetal Tigadoli 308*e3ee7b7dSSheetal Tigadoli /* MSPI: Transfer it */ 309*e3ee7b7dSSheetal Tigadoli if (bytes) 310*e3ee7b7dSSheetal Tigadoli ret = mspi_xfer(priv, bytes, tx, rx, flags); 311*e3ee7b7dSSheetal Tigadoli 312*e3ee7b7dSSheetal Tigadoli /* MSPI: Disable write lock if it's done */ 313*e3ee7b7dSSheetal Tigadoli if (flags & SPI_XFER_END) 314*e3ee7b7dSSheetal Tigadoli mmio_write_32(priv->mspi_hw + MSPI_WRITE_LOCK_REG, 0); 315*e3ee7b7dSSheetal Tigadoli 316*e3ee7b7dSSheetal Tigadoli return ret; 317*e3ee7b7dSSheetal Tigadoli } 318