static int stm32_qspi_set_mode(struct udevice *bus, uint mode) { struct stm32_qspi_priv *priv = dev_get_priv(bus); _stm32_qspi_wait_for_not_busy(priv); if ((mode & SPI_CPHA) && (mode & SPI_CPOL)) setbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CKMODE); else if (!(mode & SPI_CPHA) && !(mode & SPI_CPOL)) clrbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CKMODE); else return -ENODEV; if (mode & SPI_CS_HIGH) return -ENODEV; if (mode & SPI_RX_QUAD) priv->mode |= SPI_RX_QUAD; else if (mode & SPI_RX_DUAL) priv->mode |= SPI_RX_DUAL; else priv->mode &= ~(SPI_RX_QUAD | SPI_RX_DUAL); if (mode & SPI_TX_QUAD) priv->mode |= SPI_TX_QUAD; else if (mode & SPI_TX_DUAL) priv->mode |= SPI_TX_DUAL; else priv->mode &= ~(SPI_TX_QUAD | SPI_TX_DUAL); debug("%s: regs=%p, mode=%d rx: ", __func__, priv->regs, mode); if (mode & SPI_RX_QUAD) debug("quad, tx: "); else if (mode & SPI_RX_DUAL) debug("dual, tx: "); else debug("single, tx: "); if (mode & SPI_TX_QUAD) debug("quad\n"); else if (mode & SPI_TX_DUAL) debug("dual\n"); else debug("single\n"); return 0; }
static void _stm32_qspi_enable_mmap(struct stm32_qspi_priv *priv, struct spi_flash *flash) { priv->command = flash->read_cmd | CMD_HAS_ADR | CMD_HAS_DATA | CMD_HAS_DUMMY; priv->dummycycles = flash->dummy_byte * 8; unsigned int ccr_reg = _stm32_qspi_gen_ccr(priv); ccr_reg |= (STM32_QSPI_CCR_MEM_MAP << STM32_QSPI_CCR_FMODE_SHIFT); _stm32_qspi_wait_for_not_busy(priv); writel(ccr_reg, &priv->regs->ccr); priv->dummycycles = 0; }
static int stm32_qspi_set_speed(struct udevice *bus, uint speed) { struct stm32_qspi_platdata *plat = bus->platdata; struct stm32_qspi_priv *priv = dev_get_priv(bus); if (speed > plat->max_hz) speed = plat->max_hz; u32 qspi_clk = priv->clock_rate; u32 prescaler = 255; if (speed > 0) { prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1; if (prescaler > 255) prescaler = 255; else if (prescaler < 0) prescaler = 0; } u32 csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000); csht = (csht - 1) & STM32_QSPI_DCR_CSHT_MASK; _stm32_qspi_wait_for_not_busy(priv); clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_PRESCALER_MASK << STM32_QSPI_CR_PRESCALER_SHIFT, prescaler << STM32_QSPI_CR_PRESCALER_SHIFT); clrsetbits_le32(&priv->regs->dcr, STM32_QSPI_DCR_CSHT_MASK << STM32_QSPI_DCR_CSHT_SHIFT, csht << STM32_QSPI_DCR_CSHT_SHIFT); debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, (qspi_clk / (prescaler + 1))); return 0; }
static int _stm32_qspi_wait_cmd(struct stm32_qspi_priv *priv, const struct spi_mem_op *op) { u32 sr; int ret; if (!op->data.nbytes) return _stm32_qspi_wait_for_not_busy(priv); ret = readl_poll_timeout(&priv->regs->sr, sr, sr & STM32_QSPI_SR_TCF, STM32_QSPI_CMD_TIMEOUT_US); if (ret) { pr_err("cmd timeout (stat:%#x)\n", sr); } else if (readl(&priv->regs->sr) & STM32_QSPI_SR_TEF) { pr_err("transfer error (stat:%#x)\n", sr); ret = -EIO; } /* clear flags */ writel(STM32_QSPI_FCR_CTCF | STM32_QSPI_FCR_CTEF, &priv->regs->fcr); return ret; }
static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv, struct spi_flash *flash, unsigned int bitlen, const u8 *dout, u8 *din, unsigned long flags) { unsigned int words = bitlen / 8; if (flags & SPI_XFER_MMAP) { _stm32_qspi_enable_mmap(priv, flash); return 0; } else if (flags & SPI_XFER_MMAP_END) { _stm32_qspi_disable_mmap(priv); return 0; } if (bitlen == 0) return -1; if (bitlen % 8) { debug("spi_xfer: Non byte aligned SPI transfer\n"); return -1; } if (dout && din) { debug("spi_xfer: QSPI cannot have data in and data out set\n"); return -1; } if (!dout && (flags & SPI_XFER_BEGIN)) { debug("spi_xfer: QSPI transfer must begin with command\n"); return -1; } if (dout) { if (flags & SPI_XFER_BEGIN) { /* data is command */ priv->command = dout[0] | CMD_HAS_DATA; if (words >= 4) { /* address is here too */ priv->address = (dout[1] << 16) | (dout[2] << 8) | dout[3]; priv->command |= CMD_HAS_ADR; } if (words > 4) { /* rest is dummy bytes */ priv->dummycycles = (words - 4) * 8; priv->command |= CMD_HAS_DUMMY; } if (flags & SPI_XFER_END) { /* command without data */ priv->command &= ~(CMD_HAS_DATA); } } if (flags & SPI_XFER_END) { u32 ccr_reg = _stm32_qspi_gen_ccr(priv); ccr_reg |= STM32_QSPI_CCR_IND_WRITE << STM32_QSPI_CCR_FMODE_SHIFT; _stm32_qspi_wait_for_not_busy(priv); if (priv->command & CMD_HAS_DATA) _stm32_qspi_set_xfer_length(priv, words); _stm32_qspi_start_xfer(priv, ccr_reg); debug("%s: write: ccr:0x%08x adr:0x%08x\n", __func__, priv->regs->ccr, priv->regs->ar); if (priv->command & CMD_HAS_DATA) { _stm32_qspi_wait_for_ftf(priv); debug("%s: words:%d data:", __func__, words); int i = 0; while (words > i) { writeb(dout[i], &priv->regs->dr); debug("%02x ", dout[i]); i++; } debug("\n"); _stm32_qspi_wait_for_complete(priv); } else { _stm32_qspi_wait_for_not_busy(priv); } } } else if (din) { u32 ccr_reg = _stm32_qspi_gen_ccr(priv); ccr_reg |= STM32_QSPI_CCR_IND_READ << STM32_QSPI_CCR_FMODE_SHIFT; _stm32_qspi_wait_for_not_busy(priv); _stm32_qspi_set_xfer_length(priv, words); _stm32_qspi_start_xfer(priv, ccr_reg); debug("%s: read: ccr:0x%08x adr:0x%08x len:%d\n", __func__, priv->regs->ccr, priv->regs->ar, priv->regs->dlr); debug("%s: data:", __func__); int i = 0; while (words > i) { din[i] = readb(&priv->regs->dr); debug("%02x ", din[i]); i++; } debug("\n"); } return 0; }
static int stm32_qspi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { struct stm32_qspi_priv *priv = dev_get_priv(slave->dev->parent); u32 cr, ccr, addr_max; u8 mode = STM32_QSPI_CCR_IND_WRITE; int timeout, ret; debug("%s: cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", __func__, op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, op->dummy.buswidth, op->data.buswidth, op->addr.val, op->data.nbytes); ret = _stm32_qspi_wait_for_not_busy(priv); if (ret) return ret; addr_max = op->addr.val + op->data.nbytes + 1; if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) { if (addr_max < priv->mm_size && op->addr.buswidth) mode = STM32_QSPI_CCR_MEM_MAP; else mode = STM32_QSPI_CCR_IND_READ; } if (op->data.nbytes) writel(op->data.nbytes - 1, &priv->regs->dlr); ccr = (mode << STM32_QSPI_CCR_FMODE_SHIFT); ccr |= op->cmd.opcode; ccr |= (_stm32_qspi_get_mode(op->cmd.buswidth) << STM32_QSPI_CCR_IMODE_SHIFT); if (op->addr.nbytes) { ccr |= ((op->addr.nbytes - 1) << STM32_QSPI_CCR_ADSIZE_SHIFT); ccr |= (_stm32_qspi_get_mode(op->addr.buswidth) << STM32_QSPI_CCR_ADMODE_SHIFT); } if (op->dummy.buswidth && op->dummy.nbytes) ccr |= (op->dummy.nbytes * 8 / op->dummy.buswidth << STM32_QSPI_CCR_DCYC_SHIFT); if (op->data.nbytes) ccr |= (_stm32_qspi_get_mode(op->data.buswidth) << STM32_QSPI_CCR_DMODE_SHIFT); writel(ccr, &priv->regs->ccr); if (op->addr.nbytes && mode != STM32_QSPI_CCR_MEM_MAP) writel(op->addr.val, &priv->regs->ar); ret = _stm32_qspi_tx(priv, op, mode); /* * Abort in: * -error case * -read memory map: prefetching must be stopped if we read the last * byte of device (device size - fifo size). like device size is not * knows, the prefetching is always stop. */ if (ret || mode == STM32_QSPI_CCR_MEM_MAP) goto abort; /* Wait end of tx in indirect mode */ ret = _stm32_qspi_wait_cmd(priv, op); if (ret) goto abort; return 0; abort: setbits_le32(&priv->regs->cr, STM32_QSPI_CR_ABORT); /* Wait clear of abort bit by hw */ timeout = readl_poll_timeout(&priv->regs->cr, cr, !(cr & STM32_QSPI_CR_ABORT), STM32_ABT_TIMEOUT_US); writel(STM32_QSPI_FCR_CTCF, &priv->regs->fcr); if (ret || timeout) pr_err("%s ret:%d abort timeout:%d\n", __func__, ret, timeout); return ret; }