// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2022 Microchip Technology Inc. * Padmarao Begari * Naga Sureshkumar Relli */ #include #include #include #include #include #include #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; /* * QSPI Control register mask defines */ #define CONTROL_ENABLE BIT(0) #define CONTROL_MASTER BIT(1) #define CONTROL_XIP BIT(2) #define CONTROL_XIPADDR BIT(3) #define CONTROL_CLKIDLE BIT(10) #define CONTROL_SAMPLE_MASK GENMASK(12, 11) #define CONTROL_MODE0 BIT(13) #define CONTROL_MODE12_MASK GENMASK(15, 14) #define CONTROL_MODE12_EX_RO BIT(14) #define CONTROL_MODE12_EX_RW BIT(15) #define CONTROL_MODE12_FULL GENMASK(15, 14) #define CONTROL_FLAGSX4 BIT(16) #define CONTROL_CLKRATE_MASK GENMASK(27, 24) #define CONTROL_CLKRATE_SHIFT 24 /* * QSPI Frames register mask defines */ #define FRAMES_TOTALBYTES_MASK GENMASK(15, 0) #define FRAMES_CMDBYTES_MASK GENMASK(24, 16) #define FRAMES_CMDBYTES_SHIFT 16 #define FRAMES_SHIFT 25 #define FRAMES_IDLE_MASK GENMASK(29, 26) #define FRAMES_IDLE_SHIFT 26 #define FRAMES_FLAGBYTE BIT(30) #define FRAMES_FLAGWORD BIT(31) /* * QSPI Interrupt Enable register mask defines */ #define IEN_TXDONE BIT(0) #define IEN_RXDONE BIT(1) #define IEN_RXAVAILABLE BIT(2) #define IEN_TXAVAILABLE BIT(3) #define IEN_RXFIFOEMPTY BIT(4) #define IEN_TXFIFOFULL BIT(5) /* * QSPI Status register mask defines */ #define STATUS_TXDONE BIT(0) #define STATUS_RXDONE BIT(1) #define STATUS_RXAVAILABLE BIT(2) #define STATUS_TXAVAILABLE BIT(3) #define STATUS_RXFIFOEMPTY BIT(4) #define STATUS_TXFIFOFULL BIT(5) #define STATUS_READY BIT(7) #define STATUS_FLAGSX4 BIT(8) #define STATUS_MASK GENMASK(8, 0) #define BYTESUPPER_MASK GENMASK(31, 16) #define BYTESLOWER_MASK GENMASK(15, 0) #define MAX_DIVIDER 16 #define MIN_DIVIDER 0 #define MAX_DATA_CMD_LEN 256 /* QSPI ready time out value */ #define TIMEOUT_MS (1000 * 500) /* * QSPI Register offsets. */ #define REG_CONTROL (0x00) #define REG_FRAMES (0x04) #define REG_IEN (0x0c) #define REG_STATUS (0x10) #define REG_DIRECT_ACCESS (0x14) #define REG_UPPER_ACCESS (0x18) #define REG_RX_DATA (0x40) #define REG_TX_DATA (0x44) #define REG_X4_RX_DATA (0x48) #define REG_X4_TX_DATA (0x4c) #define REG_FRAMESUP (0x50) /** * struct mchp_coreqspi - Defines qspi driver instance * @regs: Address of the QSPI controller registers * @freq: QSPI Input frequency * @txbuf: TX buffer * @rxbuf: RX buffer * @tx_len: Number of bytes left to transfer * @rx_len: Number of bytes left to receive */ struct mchp_coreqspi { void __iomem *regs; u32 freq; u8 *txbuf; u8 *rxbuf; int tx_len; int rx_len; }; static void mchp_coreqspi_init_hw(struct mchp_coreqspi *qspi) { u32 control; control = CONTROL_CLKIDLE | CONTROL_ENABLE; writel(control, qspi->regs + REG_CONTROL); writel(0, qspi->regs + REG_IEN); } static inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi) { u32 control, data; if (!qspi->rx_len) return; control = readl(qspi->regs + REG_CONTROL); /* * Read 4-bytes from the SPI FIFO in single transaction and then read * the reamaining data byte wise. */ control |= CONTROL_FLAGSX4; writel(control, qspi->regs + REG_CONTROL); while (qspi->rx_len >= 4) { while (readl(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY) ; data = readl(qspi->regs + REG_X4_RX_DATA); *(u32 *)qspi->rxbuf = data; qspi->rxbuf += 4; qspi->rx_len -= 4; } control &= ~CONTROL_FLAGSX4; writel(control, qspi->regs + REG_CONTROL); while (qspi->rx_len--) { while (readl(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY) ; data = readl(qspi->regs + REG_RX_DATA); *qspi->rxbuf++ = (data & 0xFF); } } static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word) { u32 control, data; control = readl(qspi->regs + REG_CONTROL); control |= CONTROL_FLAGSX4; writel(control, qspi->regs + REG_CONTROL); while (qspi->tx_len >= 4) { while (readl(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) ; data = *(u32 *)qspi->txbuf; qspi->txbuf += 4; qspi->tx_len -= 4; writel(data, qspi->regs + REG_X4_TX_DATA); } control &= ~CONTROL_FLAGSX4; writel(control, qspi->regs + REG_CONTROL); while (qspi->tx_len--) { while (readl(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) ; data = *qspi->txbuf++; writel(data, qspi->regs + REG_TX_DATA); } } static inline void mchp_coreqspi_config_op(struct mchp_coreqspi *qspi, const struct spi_mem_op *op) { u32 idle_cycles = 0; int total_bytes, cmd_bytes, frames, ctrl; cmd_bytes = op->cmd.nbytes + op->addr.nbytes; total_bytes = cmd_bytes + op->data.nbytes; /* * As per the coreQSPI IP spec,the number of command and data bytes are * controlled by the frames register for each SPI sequence. This supports * the SPI flash memory read and writes sequences as below. so configure * the cmd and total bytes accordingly. * --------------------------------------------------------------------- * TOTAL BYTES | CMD BYTES | What happens | * ______________________________________________________________________ * | | | * 1 | 1 | The SPI core will transmit a single byte | * | | and receive data is discarded | * | | | * 1 | 0 | The SPI core will transmit a single byte | * | | and return a single byte | * | | | * 10 | 4 | The SPI core will transmit 4 command | * | | bytes discarding the receive data and | * | | transmits 6 dummy bytes returning the 6 | * | | received bytes and return a single byte | * | | | * 10 | 10 | The SPI core will transmit 10 command | * | | | * 10 | 0 | The SPI core will transmit 10 command | * | | bytes and returning 10 received bytes | * ______________________________________________________________________ */ if (!(op->data.dir == SPI_MEM_DATA_IN)) cmd_bytes = total_bytes; frames = total_bytes & BYTESUPPER_MASK; writel(frames, qspi->regs + REG_FRAMESUP); frames = total_bytes & BYTESLOWER_MASK; frames |= cmd_bytes << FRAMES_CMDBYTES_SHIFT; if (op->dummy.buswidth) idle_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth; frames |= idle_cycles << FRAMES_IDLE_SHIFT; ctrl = readl(qspi->regs + REG_CONTROL); if (ctrl & CONTROL_MODE12_MASK) frames |= (1 << FRAMES_SHIFT); frames |= FRAMES_FLAGWORD; writel(frames, qspi->regs + REG_FRAMES); } static int mchp_coreqspi_wait_for_ready(struct spi_slave *slave) { struct mchp_coreqspi *qspi = dev_get_priv(slave->dev->parent); unsigned long count = 0; while (1) { if (readl(qspi->regs + REG_STATUS) & STATUS_READY) return 0; udelay(1); count += 1; if (count == TIMEOUT_MS) return -ETIMEDOUT; } } static int mchp_coreqspi_set_operate_mode(struct mchp_coreqspi *qspi, const struct spi_mem_op *op) { u32 control = readl(qspi->regs + REG_CONTROL); /* * The operating mode can be configured based on the command that needs * to be send. * bits[15:14]: Sets whether multiple bit SPI operates in normal, * extended or full modes. * 00: Normal (single DQ0 TX and single DQ1 RX lines) * 01: Extended RO (command and address bytes on DQ0 only) * 10: Extended RW (command byte on DQ0 only) * 11: Full. (command and address are on all DQ lines) * bit[13]: Sets whether multiple bit SPI uses 2 or 4 bits of data * 0: 2-bits (BSPI) * 1: 4-bits (QSPI) */ if (op->data.buswidth == 4 || op->data.buswidth == 2) { control &= ~CONTROL_MODE12_MASK; if (op->cmd.buswidth == 1 && (op->addr.buswidth == 1 || op->addr.buswidth == 0)) control |= CONTROL_MODE12_EX_RO; else if (op->cmd.buswidth == 1) control |= CONTROL_MODE12_EX_RW; else control |= CONTROL_MODE12_FULL; control |= CONTROL_MODE0; } else { control &= ~(CONTROL_MODE12_MASK | CONTROL_MODE0); } writel(control, qspi->regs + REG_CONTROL); return 0; } static int mchp_coreqspi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { struct mchp_coreqspi *qspi = dev_get_priv(slave->dev->parent); u32 address = op->addr.val; u8 opcode = op->cmd.opcode; u8 opaddr[5]; int err = 0, i; err = mchp_coreqspi_wait_for_ready(slave); if (err) return err; err = mchp_coreqspi_set_operate_mode(qspi, op); if (err) return err; mchp_coreqspi_config_op(qspi, op); if (op->cmd.opcode) { qspi->txbuf = &opcode; qspi->rxbuf = NULL; qspi->tx_len = op->cmd.nbytes; qspi->rx_len = 0; mchp_coreqspi_write_op(qspi, false); } qspi->txbuf = &opaddr[0]; if (op->addr.nbytes) { for (i = 0; i < op->addr.nbytes; i++) qspi->txbuf[i] = address >> (8 * (op->addr.nbytes - i - 1)); qspi->rxbuf = NULL; qspi->tx_len = op->addr.nbytes; qspi->rx_len = 0; mchp_coreqspi_write_op(qspi, false); } if (op->data.nbytes) { if (op->data.dir == SPI_MEM_DATA_OUT) { qspi->txbuf = (u8 *)op->data.buf.out; qspi->rxbuf = NULL; qspi->rx_len = 0; qspi->tx_len = op->data.nbytes; mchp_coreqspi_write_op(qspi, true); } else { qspi->txbuf = NULL; qspi->rxbuf = (u8 *)op->data.buf.in; qspi->rx_len = op->data.nbytes; qspi->tx_len = 0; mchp_coreqspi_read_op(qspi); } } return 0; } static bool mchp_coreqspi_supports_op(struct spi_slave *slave, const struct spi_mem_op *op) { if (!spi_mem_default_supports_op(slave, op)) return false; if ((op->data.buswidth == 4 || op->data.buswidth == 2) && (op->cmd.buswidth == 1 && (op->addr.buswidth == 1 || op->addr.buswidth == 0))) { /* * If the command and address are on DQ0 only, then this * controller doesn't support sending data on dual and * quad lines. but it supports reading data on dual and * quad lines with same configuration as command and * address on DQ0. * i.e. The control register[15:13] :EX_RO(read only) is * meant only for the command and address are on DQ0 but * not to write data, it is just to read. * Ex: 0x34h is Quad Load Program Data which is not * supported. Then the spi-mem layer will iterate over * each command and it will chose the supported one. */ if (op->data.dir == SPI_MEM_DATA_OUT) return false; } return true; } static int mchp_coreqspi_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op) { if (op->data.dir == SPI_MEM_DATA_OUT) { if (op->data.nbytes > MAX_DATA_CMD_LEN) op->data.nbytes = MAX_DATA_CMD_LEN; } return 0; } static int mchp_coreqspi_set_speed(struct udevice *dev, uint speed) { struct mchp_coreqspi *qspi = dev_get_priv(dev); u32 control, baud_rate_val = 0; if (speed > (qspi->freq / 2)) speed = qspi->freq / 2; baud_rate_val = DIV_ROUND_UP(qspi->freq, 2 * speed); if (baud_rate_val >= MAX_DIVIDER || baud_rate_val <= MIN_DIVIDER) return -EINVAL; control = readl(qspi->regs + REG_CONTROL); control &= ~CONTROL_CLKRATE_MASK; control |= baud_rate_val << CONTROL_CLKRATE_SHIFT; writel(control, qspi->regs + REG_CONTROL); return 0; } static int mchp_coreqspi_set_mode(struct udevice *dev, uint mode) { struct mchp_coreqspi *qspi = dev_get_priv(dev); u32 control; control = readl(qspi->regs + REG_CONTROL); if ((mode & SPI_CPOL) && (mode & SPI_CPHA)) control |= CONTROL_CLKIDLE; else control &= ~CONTROL_CLKIDLE; writel(control, qspi->regs + REG_CONTROL); return 0; } static int mchp_coreqspi_claim_bus(struct udevice *dev) { return 0; } static int mchp_coreqspi_release_bus(struct udevice *dev) { return 0; } static int mchp_coreqspi_probe(struct udevice *dev) { struct mchp_coreqspi *qspi = dev_get_priv(dev); struct clk clk; ulong clk_rate; int ret; ret = clk_get_by_index(dev, 0, &clk); if (ret) return -EINVAL; ret = clk_enable(&clk); if (ret) return ret; clk_rate = clk_get_rate(&clk); if (!clk_rate) return -EINVAL; qspi->freq = clk_rate; qspi->regs = dev_read_addr_ptr(dev); if (!qspi->regs) return -EINVAL; /* Init the mpfs qspi hw */ mchp_coreqspi_init_hw(qspi); return 0; } static const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = { .adjust_op_size = mchp_coreqspi_adjust_op_size, .supports_op = mchp_coreqspi_supports_op, .exec_op = mchp_coreqspi_exec_op, }; static const struct dm_spi_ops mchp_coreqspi_ops = { .claim_bus = mchp_coreqspi_claim_bus, .release_bus = mchp_coreqspi_release_bus, .set_speed = mchp_coreqspi_set_speed, .set_mode = mchp_coreqspi_set_mode, .mem_ops = &mchp_coreqspi_mem_ops, }; static const struct udevice_id mchp_coreqspi_ids[] = { { .compatible = "microchip,mpfs-coreqspi-rtl-v2" }, { .compatible = "microchip,mpfs-qspi" }, { } }; U_BOOT_DRIVER(mchp_coreqspi) = { .name = "mchp_coreqspi", .id = UCLASS_SPI, .of_match = mchp_coreqspi_ids, .ops = &mchp_coreqspi_ops, .priv_auto = sizeof(struct mchp_coreqspi), .probe = mchp_coreqspi_probe, };