| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright 2020-2021 Broadcom
- */
- #include <common.h>
- #include <dm.h>
- #include <spi.h>
- #include <spi-mem.h>
- #include <asm/io.h>
- #include <linux/delay.h>
- #include <linux/err.h>
- #include <linux/iopoll.h>
- #include <linux/log2.h>
- /* Delay required to change the mode of operation */
- #define BUSY_DELAY_US 1
- #define BUSY_TIMEOUT_US 200000
- #define DWORD_ALIGNED(a) (!(((ulong)(a)) & 3))
- /* Chip attributes */
- #define QSPI_AXI_CLK 175000000
- #define SPBR_MIN 8U
- #define SPBR_MAX 255U
- #define NUM_CDRAM 16U
- #define CDRAM_PCS0 2
- #define CDRAM_CONT BIT(7)
- #define CDRAM_BITS_EN BIT(6)
- #define CDRAM_QUAD_MODE BIT(8)
- #define CDRAM_RBIT_INPUT BIT(10)
- #define MSPI_SPE BIT(6)
- #define MSPI_CONT_AFTER_CMD BIT(7)
- #define MSPI_MSTR BIT(7)
- /* Register fields */
- #define MSPI_SPCR0_MSB_BITS_8 0x00000020
- #define BSPI_RAF_CONTROL_START_MASK 0x00000001
- #define BSPI_RAF_STATUS_SESSION_BUSY_MASK 0x00000001
- #define BSPI_RAF_STATUS_FIFO_EMPTY_MASK 0x00000002
- #define BSPI_STRAP_OVERRIDE_DATA_QUAD_SHIFT 3
- #define BSPI_STRAP_OVERRIDE_4BYTE_SHIFT 2
- #define BSPI_STRAP_OVERRIDE_DATA_DUAL_SHIFT 1
- #define BSPI_STRAP_OVERRIDE_SHIFT 0
- #define BSPI_BPC_DATA_SHIFT 0
- #define BSPI_BPC_MODE_SHIFT 8
- #define BSPI_BPC_ADDR_SHIFT 16
- #define BSPI_BPC_CMD_SHIFT 24
- #define BSPI_BPP_ADDR_SHIFT 16
- /* MSPI registers */
- #define MSPI_SPCR0_LSB_REG 0x000
- #define MSPI_SPCR0_MSB_REG 0x004
- #define MSPI_SPCR1_LSB_REG 0x008
- #define MSPI_SPCR1_MSB_REG 0x00c
- #define MSPI_NEWQP_REG 0x010
- #define MSPI_ENDQP_REG 0x014
- #define MSPI_SPCR2_REG 0x018
- #define MSPI_STATUS_REG 0x020
- #define MSPI_CPTQP_REG 0x024
- #define MSPI_TX_REG 0x040
- #define MSPI_RX_REG 0x0c0
- #define MSPI_CDRAM_REG 0x140
- #define MSPI_WRITE_LOCK_REG 0x180
- #define MSPI_DISABLE_FLUSH_GEN_REG 0x184
- /* BSPI registers */
- #define BSPI_REVISION_ID_REG 0x000
- #define BSPI_SCRATCH_REG 0x004
- #define BSPI_MAST_N_BOOT_CTRL_REG 0x008
- #define BSPI_BUSY_STATUS_REG 0x00c
- #define BSPI_INTR_STATUS_REG 0x010
- #define BSPI_B0_STATUS_REG 0x014
- #define BSPI_B0_CTRL_REG 0x018
- #define BSPI_B1_STATUS_REG 0x01c
- #define BSPI_B1_CTRL_REG 0x020
- #define BSPI_STRAP_OVERRIDE_CTRL_REG 0x024
- #define BSPI_FLEX_MODE_ENABLE_REG 0x028
- #define BSPI_BITS_PER_CYCLE_REG 0x02C
- #define BSPI_BITS_PER_PHASE_REG 0x030
- #define BSPI_CMD_AND_MODE_BYTE_REG 0x034
- #define BSPI_FLASH_UPPER_ADDR_BYTE_REG 0x038
- #define BSPI_XOR_VALUE_REG 0x03C
- #define BSPI_XOR_ENABLE_REG 0x040
- #define BSPI_PIO_MODE_ENABLE_REG 0x044
- #define BSPI_PIO_IODIR_REG 0x048
- #define BSPI_PIO_DATA_REG 0x04C
- /* RAF registers */
- #define BSPI_RAF_START_ADDRESS_REG 0x00
- #define BSPI_RAF_NUM_WORDS_REG 0x04
- #define BSPI_RAF_CTRL_REG 0x08
- #define BSPI_RAF_FULLNESS_REG 0x0C
- #define BSPI_RAF_WATERMARK_REG 0x10
- #define BSPI_RAF_STATUS_REG 0x14
- #define BSPI_RAF_READ_DATA_REG 0x18
- #define BSPI_RAF_WORD_CNT_REG 0x1C
- #define BSPI_RAF_CURR_ADDR_REG 0x20
- #define XFER_DUAL BIT(30)
- #define XFER_QUAD BIT(31)
- #define FLUSH_BIT BIT(0)
- #define MAST_N_BOOT_BIT BIT(0)
- #define WRITE_LOCK_BIT BIT(0)
- #define CEIL(m, n) (((m) + (n) - 1) / (n))
- #define UPPER_BYTE_MASK 0xFF000000
- #define SIZE_16MB 0x001000000
- /*
- * struct bcmspi_priv - qspi private structure
- *
- * @bspi_addr: bspi read address
- * @bspi_4byte_addr: bspi 4 byte address mode
- * @mspi: mspi registers block address
- * @bspi: bspi registers block address
- * @bspi_raf: bspi raf registers block address
- */
- struct bcmspi_priv {
- u32 bspi_addr;
- bool bspi_4byte_addr;
- fdt_addr_t mspi;
- fdt_addr_t bspi;
- fdt_addr_t bspi_raf;
- };
- /* BSPI mode */
- static void bspi_flush_prefetch_buffers(struct bcmspi_priv *priv)
- {
- writel(0, priv->bspi + BSPI_B0_CTRL_REG);
- writel(0, priv->bspi + BSPI_B1_CTRL_REG);
- writel(FLUSH_BIT, priv->bspi + BSPI_B0_CTRL_REG);
- writel(FLUSH_BIT, priv->bspi + BSPI_B1_CTRL_REG);
- }
- static int bspi_enable(struct bcmspi_priv *priv)
- {
- /* Disable write lock */
- writel(0, priv->mspi + MSPI_WRITE_LOCK_REG);
- /* Flush prefetch buffers */
- bspi_flush_prefetch_buffers(priv);
- /* Switch to BSPI */
- writel(0, priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG);
- return 0;
- }
- static int bspi_disable(struct bcmspi_priv *priv)
- {
- int ret;
- uint val;
- if ((readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG) & 1) == 0) {
- ret = readl_poll_timeout(priv->bspi + BSPI_BUSY_STATUS_REG, val, !(val & 1),
- BUSY_TIMEOUT_US);
- if (ret) {
- printf("%s: Failed to disable bspi, device busy\n", __func__);
- return ret;
- }
- /* Switch to MSPI */
- writel(MAST_N_BOOT_BIT, priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG);
- udelay(BUSY_DELAY_US);
- val = readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG);
- if (!(val & 1)) {
- printf("%s: Failed to enable mspi\n", __func__);
- return -EBUSY;
- }
- }
- /* Enable write lock */
- writel(WRITE_LOCK_BIT, priv->mspi + MSPI_WRITE_LOCK_REG);
- return 0;
- }
- static int bspi_read_via_raf(struct bcmspi_priv *priv, u8 *rx, uint bytes)
- {
- u32 status;
- uint words;
- int aligned;
- int ret;
- /*
- * Flush data from the previous session (unlikely)
- * Read outstanding bits in the poll condition to empty FIFO
- */
- ret = readl_poll_timeout(priv->bspi_raf + BSPI_RAF_STATUS_REG,
- status,
- (!readl(priv->bspi_raf + BSPI_RAF_READ_DATA_REG) &&
- status & BSPI_RAF_STATUS_FIFO_EMPTY_MASK) &&
- !(status & BSPI_RAF_STATUS_SESSION_BUSY_MASK),
- BUSY_TIMEOUT_US);
- if (ret) {
- printf("%s: Failed to flush fifo\n", __func__);
- return ret;
- }
- /* Transfer is in words */
- words = CEIL(bytes, 4);
- /* Setup hardware */
- if (priv->bspi_4byte_addr) {
- u32 val = priv->bspi_addr & UPPER_BYTE_MASK;
- if (val != readl(priv->bspi + BSPI_FLASH_UPPER_ADDR_BYTE_REG)) {
- writel(val, priv->bspi + BSPI_FLASH_UPPER_ADDR_BYTE_REG);
- bspi_flush_prefetch_buffers(priv);
- }
- }
- writel(priv->bspi_addr & ~UPPER_BYTE_MASK, priv->bspi_raf + BSPI_RAF_START_ADDRESS_REG);
- writel(words, priv->bspi_raf + BSPI_RAF_NUM_WORDS_REG);
- writel(0, priv->bspi_raf + BSPI_RAF_WATERMARK_REG);
- /* Start reading */
- writel(BSPI_RAF_CONTROL_START_MASK, priv->bspi_raf + BSPI_RAF_CTRL_REG);
- aligned = DWORD_ALIGNED(rx);
- while (bytes) {
- status = readl(priv->bspi_raf + BSPI_RAF_STATUS_REG);
- if (!(status & BSPI_RAF_STATUS_FIFO_EMPTY_MASK)) {
- /* RAF is LE only, convert data to host endianness */
- u32 data = le32_to_cpu(readl(priv->bspi_raf + BSPI_RAF_READ_DATA_REG));
- /* Check if we can use the whole word */
- if (aligned && bytes >= 4) {
- *(u32 *)rx = data;
- rx += 4;
- bytes -= 4;
- } else {
- uint chunk = min(bytes, 4U);
- /* Read out bytes one by one */
- while (chunk) {
- *rx++ = (u8)data;
- data >>= 8;
- chunk--;
- bytes--;
- }
- }
- continue;
- }
- if (!(status & BSPI_RAF_STATUS_SESSION_BUSY_MASK)) {
- /* FIFO is empty and the session is done */
- break;
- }
- }
- return 0;
- }
- static int bspi_read(struct bcmspi_priv *priv, u8 *rx, uint bytes)
- {
- int ret;
- /* Transfer data */
- while (bytes > 0) {
- /* Special handing since RAF cannot go across 16MB boundary */
- uint trans = bytes;
- /* Divide into multiple transfers if it goes across the 16MB boundary */
- if (priv->bspi_4byte_addr && (priv->bspi_addr >> 24) !=
- ((priv->bspi_addr + bytes) >> 24))
- trans = SIZE_16MB - (priv->bspi_addr & ~UPPER_BYTE_MASK);
- ret = bspi_read_via_raf(priv, rx, trans);
- if (ret)
- return ret;
- priv->bspi_addr += trans;
- rx += trans;
- bytes -= trans;
- }
- bspi_flush_prefetch_buffers(priv);
- return 0;
- }
- static void bspi_set_flex_mode(struct bcmspi_priv *priv, const struct spi_mem_op *op)
- {
- int bpp = (op->dummy.nbytes * 8) / op->dummy.buswidth;
- int cmd = op->cmd.opcode;
- int bpc = ilog2(op->data.buswidth) << BSPI_BPC_DATA_SHIFT |
- ilog2(op->addr.buswidth) << BSPI_BPC_ADDR_SHIFT |
- ilog2(op->cmd.buswidth) << BSPI_BPC_CMD_SHIFT;
- int so = BIT(BSPI_STRAP_OVERRIDE_SHIFT) |
- (op->data.buswidth > 1) << BSPI_STRAP_OVERRIDE_DATA_DUAL_SHIFT |
- (op->addr.nbytes > 3) << BSPI_STRAP_OVERRIDE_4BYTE_SHIFT |
- (op->data.buswidth > 3) << BSPI_STRAP_OVERRIDE_DATA_QUAD_SHIFT;
- /* Disable flex mode first */
- writel(0, priv->bspi + BSPI_FLEX_MODE_ENABLE_REG);
- /* Configure single, dual or quad mode */
- writel(bpc, priv->bspi + BSPI_BITS_PER_CYCLE_REG);
- /* Opcode */
- writel(cmd, priv->bspi + BSPI_CMD_AND_MODE_BYTE_REG);
- /* Count of dummy cycles */
- writel(bpp, priv->bspi + BSPI_BITS_PER_PHASE_REG);
- /* Enable 4-byte address */
- if (priv->bspi_4byte_addr) {
- setbits_le32(priv->bspi + BSPI_BITS_PER_PHASE_REG, BIT(BSPI_BPP_ADDR_SHIFT));
- } else {
- clrbits_le32(priv->bspi + BSPI_BITS_PER_PHASE_REG, BIT(BSPI_BPP_ADDR_SHIFT));
- writel(0, priv->bspi + BSPI_FLASH_UPPER_ADDR_BYTE_REG);
- }
- /* Enable flex mode to take effect */
- writel(1, priv->bspi + BSPI_FLEX_MODE_ENABLE_REG);
- /* Flush prefetch buffers since 32MB window BSPI could be used */
- bspi_flush_prefetch_buffers(priv);
- /* Override the strap settings */
- writel(so, priv->bspi + BSPI_STRAP_OVERRIDE_CTRL_REG);
- }
- static int bspi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
- {
- struct udevice *bus = dev_get_parent(slave->dev);
- struct bcmspi_priv *priv = dev_get_priv(bus);
- int ret = -ENOTSUPP;
- /* BSPI read */
- if (op->data.dir == SPI_MEM_DATA_IN &&
- op->data.nbytes && op->addr.nbytes) {
- priv->bspi_4byte_addr = (op->addr.nbytes > 3);
- priv->bspi_addr = op->addr.val;
- bspi_set_flex_mode(priv, op);
- ret = bspi_read(priv, op->data.buf.in, op->data.nbytes);
- }
- return ret;
- }
- static const struct spi_controller_mem_ops bspi_mem_ops = {
- .exec_op = bspi_exec_op,
- };
- /* MSPI mode */
- static int mspi_exec(struct bcmspi_priv *priv, uint bytes, const u8 *tx, u8 *rx, ulong flags)
- {
- u32 cdr = CDRAM_PCS0 | CDRAM_CONT;
- bool use_16bits = !(bytes & 1);
- if (flags & XFER_QUAD) {
- cdr |= CDRAM_QUAD_MODE;
- if (!tx)
- cdr |= CDRAM_RBIT_INPUT;
- }
- while (bytes) {
- uint chunk;
- uint queues;
- uint i;
- uint val;
- int ret;
- if (use_16bits) {
- chunk = min(bytes, NUM_CDRAM * 2);
- queues = (chunk + 1) / 2;
- bytes -= chunk;
- /* Fill CDRAMs */
- for (i = 0; i < queues; i++)
- writel(cdr | CDRAM_BITS_EN, priv->mspi + MSPI_CDRAM_REG + 4 * i);
- /* Fill TXRAMs */
- for (i = 0; i < chunk; i++)
- writel(tx ? tx[i] : 0xff, priv->mspi + MSPI_TX_REG + 4 * i);
- } else {
- /* Determine how many bytes to process this time */
- chunk = min(bytes, NUM_CDRAM);
- queues = chunk;
- bytes -= chunk;
- /* Fill CDRAMs and TXRAMS */
- for (i = 0; i < chunk; i++) {
- writel(cdr, priv->mspi + MSPI_CDRAM_REG + 4 * i);
- writel(tx ? tx[i] : 0xff, priv->mspi + MSPI_TX_REG + 8 * i);
- }
- }
- /* Setup queue pointers */
- writel(0, priv->mspi + MSPI_NEWQP_REG);
- writel(queues - 1, priv->mspi + MSPI_ENDQP_REG);
- /* Deassert CS if requested and it's the last transfer */
- if (bytes == 0 && (flags & SPI_XFER_END))
- clrbits_le32(priv->mspi + MSPI_CDRAM_REG + ((queues - 1) << 2), CDRAM_CONT);
- /* Kick off */
- writel(0, priv->mspi + MSPI_STATUS_REG);
- if (bytes == 0 && (flags & SPI_XFER_END))
- writel(MSPI_SPE, priv->mspi + MSPI_SPCR2_REG);
- else
- writel(MSPI_SPE | MSPI_CONT_AFTER_CMD,
- priv->mspi + MSPI_SPCR2_REG);
- ret = readl_poll_timeout(priv->mspi + MSPI_STATUS_REG, val, (val & 1),
- BUSY_TIMEOUT_US);
- if (ret) {
- printf("%s: Failed to disable bspi, device busy\n", __func__);
- return ret;
- }
- /* Read data out */
- if (rx) {
- if (use_16bits) {
- for (i = 0; i < chunk; i++)
- rx[i] = readl(priv->mspi + MSPI_RX_REG + 4 * i) & 0xff;
- } else {
- for (i = 0; i < chunk; i++)
- rx[i] = readl(priv->mspi + MSPI_RX_REG + 8 * i + 4) & 0xff;
- }
- }
- /* Advance pointers */
- if (tx)
- tx += chunk;
- if (rx)
- rx += chunk;
- }
- return 0;
- }
- static int mspi_xfer(struct udevice *dev, uint bitlen, const void *dout, void *din, ulong flags)
- {
- struct udevice *bus = dev_get_parent(dev);
- struct bcmspi_priv *priv = dev_get_priv(bus);
- uint bytes;
- int ret = 0;
- /* we can only transfer multiples of 8 bits */
- if (bitlen % 8)
- return -EPROTONOSUPPORT;
- bytes = bitlen / 8;
- if (flags & SPI_XFER_BEGIN) {
- /* Switch to MSPI */
- ret = bspi_disable(priv);
- if (ret)
- return ret;
- }
- /* MSPI: Transfer */
- if (bytes)
- ret = mspi_exec(priv, bytes, dout, din, flags);
- if (flags & SPI_XFER_END) {
- /* Switch back to BSPI */
- ret = bspi_enable(priv);
- if (ret)
- return ret;
- }
- return ret;
- }
- /* iProc interface */
- static int iproc_qspi_set_speed(struct udevice *bus, uint speed)
- {
- struct bcmspi_priv *priv = dev_get_priv(bus);
- uint spbr;
- /* MSPI: SCK configuration */
- spbr = (QSPI_AXI_CLK - 1) / (2 * speed) + 1;
- writel(max(min(spbr, SPBR_MAX), SPBR_MIN), priv->mspi + MSPI_SPCR0_LSB_REG);
- return 0;
- }
- static int iproc_qspi_set_mode(struct udevice *bus, uint mode)
- {
- struct bcmspi_priv *priv = dev_get_priv(bus);
- /* MSPI: set master bit and mode */
- writel(MSPI_MSTR /* Master */ | (mode & 3), priv->mspi + MSPI_SPCR0_MSB_REG);
- return 0;
- }
- static int iproc_qspi_claim_bus(struct udevice *dev)
- {
- /* Nothing to do */
- return 0;
- }
- static int iproc_qspi_release_bus(struct udevice *dev)
- {
- struct udevice *bus = dev_get_parent(dev);
- struct bcmspi_priv *priv = dev_get_priv(bus);
- /* Make sure no operation is in progress */
- writel(0, priv->mspi + MSPI_SPCR2_REG);
- udelay(BUSY_DELAY_US);
- return 0;
- }
- static int iproc_qspi_of_to_plat(struct udevice *bus)
- {
- struct bcmspi_priv *priv = dev_get_priv(bus);
- priv->bspi = dev_read_addr_name(bus, "bspi");
- if (IS_ERR((void *)priv->bspi)) {
- printf("%s: Failed to get bspi base address\n", __func__);
- return PTR_ERR((void *)priv->bspi);
- }
- priv->bspi_raf = dev_read_addr_name(bus, "bspi_raf");
- if (IS_ERR((void *)priv->bspi_raf)) {
- printf("%s: Failed to get bspi_raf base address\n", __func__);
- return PTR_ERR((void *)priv->bspi_raf);
- }
- priv->mspi = dev_read_addr_name(bus, "mspi");
- if (IS_ERR((void *)priv->mspi)) {
- printf("%s: Failed to get mspi base address\n", __func__);
- return PTR_ERR((void *)priv->mspi);
- }
- return 0;
- }
- static int iproc_qspi_probe(struct udevice *bus)
- {
- struct bcmspi_priv *priv = dev_get_priv(bus);
- /* configure mspi */
- writel(0, priv->mspi + MSPI_SPCR1_LSB_REG);
- writel(0, priv->mspi + MSPI_SPCR1_MSB_REG);
- writel(0, priv->mspi + MSPI_NEWQP_REG);
- writel(0, priv->mspi + MSPI_ENDQP_REG);
- writel(0, priv->mspi + MSPI_SPCR2_REG);
- /* configure bspi */
- bspi_enable(priv);
- return 0;
- }
- static const struct dm_spi_ops iproc_qspi_ops = {
- .claim_bus = iproc_qspi_claim_bus,
- .release_bus = iproc_qspi_release_bus,
- .xfer = mspi_xfer,
- .set_speed = iproc_qspi_set_speed,
- .set_mode = iproc_qspi_set_mode,
- .mem_ops = &bspi_mem_ops,
- };
- static const struct udevice_id iproc_qspi_ids[] = {
- { .compatible = "brcm,iproc-qspi" },
- { }
- };
- U_BOOT_DRIVER(iproc_qspi) = {
- .name = "iproc_qspi",
- .id = UCLASS_SPI,
- .of_match = iproc_qspi_ids,
- .ops = &iproc_qspi_ops,
- .of_to_plat = iproc_qspi_of_to_plat,
- .priv_auto = sizeof(struct bcmspi_priv),
- .probe = iproc_qspi_probe,
- };
|