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