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