[U-Boot] [PATCH v4 0/6] Add spi-mem driver for MediaTek MT7629 SoC

Since u-boot has added the spi-mem framework and replaced the spi-nor framework, the mtk_qspi is no longer compatible with the new spi-nor driver.
This patch series add a new spi-mem driver to replace the mtk_qspi driver, with one patch to fix watchdog not feeding during spi operation.
Weijie Gao (6): mtd: spi-nor: add watchdog reset to flash operation loops spi: remove obsolete mtk_qspi driver spi: add spi-mem driver for MediaTek MT7629 SoC arm: dts: change MT7629 to use spi-mem rather than qspi configs: mt7629_rfb: change MTK_QSPI to MTK_SNFI_SPI MAINTAINERS: change spi driver entry
MAINTAINERS | 2 +- arch/arm/dts/mt7629-rfb.dts | 18 +- arch/arm/dts/mt7629.dtsi | 14 +- configs/mt7629_rfb_defconfig | 2 +- drivers/mtd/spi/spi-nor-core.c | 13 ++ drivers/mtd/spi/spi-nor-tiny.c | 3 + drivers/spi/Kconfig | 15 +- drivers/spi/Makefile | 2 +- drivers/spi/mtk_qspi.c | 359 --------------------------------- drivers/spi/mtk_snfi_spi.c | 315 +++++++++++++++++++++++++++++ 10 files changed, 365 insertions(+), 378 deletions(-) delete mode 100644 drivers/spi/mtk_qspi.c create mode 100644 drivers/spi/mtk_snfi_spi.c

This patch adds WATCHDOG_RESET() to loops for read/write/erase to avoid watchdog not being feeded in a long period.
Cc: Vignesh Raghavendra vigneshr@ti.com Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- drivers/mtd/spi/spi-nor-core.c | 13 +++++++++++++ drivers/mtd/spi/spi-nor-tiny.c | 3 +++ 2 files changed, 16 insertions(+)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 1acff745d1a..2049661f3ad 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <watchdog.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/log2.h> @@ -103,6 +104,8 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, op.addr.val += op.data.nbytes; remaining -= op.data.nbytes; op.data.buf.in += op.data.nbytes; + + WATCHDOG_RESET(); }
return len; @@ -571,6 +574,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) ret = spi_nor_wait_till_ready(nor); if (ret) goto erase_err; + + WATCHDOG_RESET(); }
erase_err: @@ -963,6 +968,9 @@ static int sst_write_byteprogram(struct spi_nor *nor, loff_t to, size_t len, if (ret) goto sst_write_err; to++; + + if (actual % 0x100 == 0) + WATCHDOG_RESET(); }
sst_write_err: @@ -1014,6 +1022,9 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, goto sst_write_err; to += 2; nor->sst_write_second = true; + + if (actual % 0x100 == 0) + WATCHDOG_RESET(); } nor->sst_write_second = false;
@@ -1094,6 +1105,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, goto write_err; *retlen += written; i += written; + + WATCHDOG_RESET(); }
write_err: diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index c19d468d62c..197a796b8af 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <watchdog.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/log2.h> @@ -103,6 +104,8 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, op.addr.val += op.data.nbytes; remaining -= op.data.nbytes; op.data.buf.in += op.data.nbytes; + + WATCHDOG_RESET(); }
return len;

+ Vignesh
On Wed, Jul 10, 2019 at 8:49 AM Weijie Gao weijie.gao@mediatek.com wrote:
This patch adds WATCHDOG_RESET() to loops for read/write/erase to avoid watchdog not being feeded in a long period.
Cc: Vignesh Raghavendra vigneshr@ti.com Signed-off-by: Weijie Gao weijie.gao@mediatek.com
drivers/mtd/spi/spi-nor-core.c | 13 +++++++++++++ drivers/mtd/spi/spi-nor-tiny.c | 3 +++ 2 files changed, 16 insertions(+)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 1acff745d1a..2049661f3ad 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -10,6 +10,7 @@ */
#include <common.h> +#include <watchdog.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/log2.h> @@ -103,6 +104,8 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len, op.addr.val += op.data.nbytes; remaining -= op.data.nbytes; op.data.buf.in += op.data.nbytes;
WATCHDOG_RESET(); }
Not sure, but it would require better testing.

Since u-boot has added the spi-mem framework and replaced the spi-nor framework, the mtk_qspi is no longer compatible with the new spi-nor driver.
Remove this driver, and a new driver will be added later.
Cc: Jagan Teki jagan@openedev.com Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- Changes since v1: none --- drivers/spi/Kconfig | 8 - drivers/spi/Makefile | 1 - drivers/spi/mtk_qspi.c | 359 ----------------------------------------- 3 files changed, 368 deletions(-) delete mode 100644 drivers/spi/mtk_qspi.c
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 9469147152a..95a63065251 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -150,14 +150,6 @@ config MT7621_SPI the SPI NOR flash on platforms embedding this Ralink / MediaTek SPI core, like MT7621/7628/7688.
-config MTK_QSPI - bool "Mediatek QSPI driver" - imply SPI_FLASH_BAR - help - Enable the Mediatek QSPI driver. This driver can be - used to access the SPI NOR flash on platforms embedding this - Mediatek QSPI IP core. - config MVEBU_A3700_SPI bool "Marvell Armada 3700 SPI driver" select CLK_ARMADA_3720 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3f9f2fab2b9..bbec33aa06e 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o -obj-$(CONFIG_MTK_QSPI) += mtk_qspi.o obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o obj-$(CONFIG_MSCC_BB_SPI) += mscc_bb_spi.o obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o diff --git a/drivers/spi/mtk_qspi.c b/drivers/spi/mtk_qspi.c deleted file mode 100644 index b510733e92c..00000000000 --- a/drivers/spi/mtk_qspi.c +++ /dev/null @@ -1,359 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2018 MediaTek, Inc. - * Author : Guochun.Mao@mediatek.com - */ - -#include <common.h> -#include <dm.h> -#include <malloc.h> -#include <spi.h> -#include <asm/io.h> -#include <linux/iopoll.h> -#include <linux/ioport.h> - -/* Register Offset */ -struct mtk_qspi_regs { - u32 cmd; - u32 cnt; - u32 rdsr; - u32 rdata; - u32 radr[3]; - u32 wdata; - u32 prgdata[6]; - u32 shreg[10]; - u32 cfg[2]; - u32 shreg10; - u32 mode_mon; - u32 status[4]; - u32 flash_time; - u32 flash_cfg; - u32 reserved_0[3]; - u32 sf_time; - u32 pp_dw_data; - u32 reserved_1; - u32 delsel_0[2]; - u32 intrstus; - u32 intren; - u32 reserved_2; - u32 cfg3; - u32 reserved_3; - u32 chksum; - u32 aaicmd; - u32 wrprot; - u32 radr3; - u32 dual; - u32 delsel_1[3]; -}; - -struct mtk_qspi_platdata { - fdt_addr_t reg_base; - fdt_addr_t mem_base; -}; - -struct mtk_qspi_priv { - struct mtk_qspi_regs *regs; - unsigned long *mem_base; - u8 op; - u8 tx[3]; /* only record max 3 bytes paras, when it's address. */ - u32 txlen; /* dout buffer length - op code length */ - u8 *rx; - u32 rxlen; -}; - -#define MTK_QSPI_CMD_POLLINGREG_US 500000 -#define MTK_QSPI_WRBUF_SIZE 256 -#define MTK_QSPI_COMMAND_ENABLE 0x30 - -/* NOR flash controller commands */ -#define MTK_QSPI_RD_TRIGGER BIT(0) -#define MTK_QSPI_READSTATUS BIT(1) -#define MTK_QSPI_PRG_CMD BIT(2) -#define MTK_QSPI_WR_TRIGGER BIT(4) -#define MTK_QSPI_WRITESTATUS BIT(5) -#define MTK_QSPI_AUTOINC BIT(7) - -#define MTK_QSPI_MAX_RX_TX_SHIFT 0x6 -#define MTK_QSPI_MAX_SHIFT 0x8 - -#define MTK_QSPI_WR_BUF_ENABLE 0x1 -#define MTK_QSPI_WR_BUF_DISABLE 0x0 - -static int mtk_qspi_execute_cmd(struct mtk_qspi_priv *priv, u8 cmd) -{ - u8 tmp; - u8 val = cmd & ~MTK_QSPI_AUTOINC; - - writeb(cmd, &priv->regs->cmd); - - return readb_poll_timeout(&priv->regs->cmd, tmp, !(val & tmp), - MTK_QSPI_CMD_POLLINGREG_US); -} - -static int mtk_qspi_tx_rx(struct mtk_qspi_priv *priv) -{ - int len = 1 + priv->txlen + priv->rxlen; - int i, ret, idx; - - if (len > MTK_QSPI_MAX_SHIFT) - return -ERR_INVAL; - - writeb(len * 8, &priv->regs->cnt); - - /* start at PRGDATA5, go down to PRGDATA0 */ - idx = MTK_QSPI_MAX_RX_TX_SHIFT - 1; - - /* opcode */ - writeb(priv->op, &priv->regs->prgdata[idx]); - idx--; - - /* program TX data */ - for (i = 0; i < priv->txlen; i++, idx--) - writeb(priv->tx[i], &priv->regs->prgdata[idx]); - - /* clear out rest of TX registers */ - while (idx >= 0) { - writeb(0, &priv->regs->prgdata[idx]); - idx--; - } - - ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_PRG_CMD); - if (ret) - return ret; - - /* restart at first RX byte */ - idx = priv->rxlen - 1; - - /* read out RX data */ - for (i = 0; i < priv->rxlen; i++, idx--) - priv->rx[i] = readb(&priv->regs->shreg[idx]); - - return 0; -} - -static int mtk_qspi_read(struct mtk_qspi_priv *priv, - u32 addr, u8 *buf, u32 len) -{ - memcpy(buf, (u8 *)priv->mem_base + addr, len); - return 0; -} - -static void mtk_qspi_set_addr(struct mtk_qspi_priv *priv, u32 addr) -{ - int i; - - for (i = 0; i < 3; i++) { - writeb(addr & 0xff, &priv->regs->radr[i]); - addr >>= 8; - } -} - -static int mtk_qspi_write_single_byte(struct mtk_qspi_priv *priv, - u32 addr, u32 length, const u8 *data) -{ - int i, ret; - - mtk_qspi_set_addr(priv, addr); - - for (i = 0; i < length; i++) { - writeb(*data++, &priv->regs->wdata); - ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER); - if (ret < 0) - return ret; - } - return 0; -} - -static int mtk_qspi_write_buffer(struct mtk_qspi_priv *priv, u32 addr, - const u8 *buf) -{ - int i, data; - - mtk_qspi_set_addr(priv, addr); - - for (i = 0; i < MTK_QSPI_WRBUF_SIZE; i += 4) { - data = buf[i + 3] << 24 | buf[i + 2] << 16 | - buf[i + 1] << 8 | buf[i]; - writel(data, &priv->regs->pp_dw_data); - } - - return mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER); -} - -static int mtk_qspi_write(struct mtk_qspi_priv *priv, - u32 addr, const u8 *buf, u32 len) -{ - int ret; - - /* setting pre-fetch buffer for page program */ - writel(MTK_QSPI_WR_BUF_ENABLE, &priv->regs->cfg[1]); - while (len >= MTK_QSPI_WRBUF_SIZE) { - ret = mtk_qspi_write_buffer(priv, addr, buf); - if (ret < 0) - return ret; - - len -= MTK_QSPI_WRBUF_SIZE; - addr += MTK_QSPI_WRBUF_SIZE; - buf += MTK_QSPI_WRBUF_SIZE; - } - /* disable pre-fetch buffer for page program */ - writel(MTK_QSPI_WR_BUF_DISABLE, &priv->regs->cfg[1]); - - if (len) - return mtk_qspi_write_single_byte(priv, addr, len, buf); - - return 0; -} - -static int mtk_qspi_claim_bus(struct udevice *dev) -{ - /* nothing to do */ - return 0; -} - -static int mtk_qspi_release_bus(struct udevice *dev) -{ - /* nothing to do */ - return 0; -} - -static int mtk_qspi_transfer(struct mtk_qspi_priv *priv, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) -{ - u32 bytes = DIV_ROUND_UP(bitlen, 8); - u32 addr; - - if (!bytes) - return -ERR_INVAL; - - if (dout) { - if (flags & SPI_XFER_BEGIN) { - /* parse op code and potential paras first */ - priv->op = *(u8 *)dout; - if (bytes > 1) - memcpy(priv->tx, (u8 *)dout + 1, - bytes <= 4 ? bytes - 1 : 3); - priv->txlen = bytes - 1; - } - - if (flags == SPI_XFER_ONCE) { - /* operations without receiving or sending data. - * for example: erase, write flash register or write - * enable... - */ - priv->rx = NULL; - priv->rxlen = 0; - return mtk_qspi_tx_rx(priv); - } - - if (flags & SPI_XFER_END) { - /* here, dout should be data to be written. - * and priv->tx should be filled 3Bytes address. - */ - addr = priv->tx[0] << 16 | priv->tx[1] << 8 | - priv->tx[2]; - return mtk_qspi_write(priv, addr, (u8 *)dout, bytes); - } - } - - if (din) { - if (priv->txlen >= 3) { - /* if run to here, priv->tx[] should be the address - * where read data from, - * and, din is the buf to receive data. - */ - addr = priv->tx[0] << 16 | priv->tx[1] << 8 | - priv->tx[2]; - return mtk_qspi_read(priv, addr, (u8 *)din, bytes); - } - - /* should be reading flash's register */ - priv->rx = (u8 *)din; - priv->rxlen = bytes; - return mtk_qspi_tx_rx(priv); - } - - return 0; -} - -static int mtk_qspi_xfer(struct udevice *dev, unsigned int bitlen, - const void *dout, void *din, unsigned long flags) -{ - struct udevice *bus = dev->parent; - struct mtk_qspi_priv *priv = dev_get_priv(bus); - - return mtk_qspi_transfer(priv, bitlen, dout, din, flags); -} - -static int mtk_qspi_set_speed(struct udevice *bus, uint speed) -{ - /* nothing to do */ - return 0; -} - -static int mtk_qspi_set_mode(struct udevice *bus, uint mode) -{ - /* nothing to do */ - return 0; -} - -static int mtk_qspi_ofdata_to_platdata(struct udevice *bus) -{ - struct resource res_reg, res_mem; - struct mtk_qspi_platdata *plat = bus->platdata; - int ret; - - ret = dev_read_resource_byname(bus, "reg_base", &res_reg); - if (ret) { - debug("can't get reg_base resource(ret = %d)\n", ret); - return -ENOMEM; - } - - ret = dev_read_resource_byname(bus, "mem_base", &res_mem); - if (ret) { - debug("can't get map_base resource(ret = %d)\n", ret); - return -ENOMEM; - } - - plat->mem_base = res_mem.start; - plat->reg_base = res_reg.start; - - return 0; -} - -static int mtk_qspi_probe(struct udevice *bus) -{ - struct mtk_qspi_platdata *plat = dev_get_platdata(bus); - struct mtk_qspi_priv *priv = dev_get_priv(bus); - - priv->regs = (struct mtk_qspi_regs *)plat->reg_base; - priv->mem_base = (unsigned long *)plat->mem_base; - - writel(MTK_QSPI_COMMAND_ENABLE, &priv->regs->wrprot); - - return 0; -} - -static const struct dm_spi_ops mtk_qspi_ops = { - .claim_bus = mtk_qspi_claim_bus, - .release_bus = mtk_qspi_release_bus, - .xfer = mtk_qspi_xfer, - .set_speed = mtk_qspi_set_speed, - .set_mode = mtk_qspi_set_mode, -}; - -static const struct udevice_id mtk_qspi_ids[] = { - { .compatible = "mediatek,mt7629-qspi" }, - { } -}; - -U_BOOT_DRIVER(mtk_qspi) = { - .name = "mtk_qspi", - .id = UCLASS_SPI, - .of_match = mtk_qspi_ids, - .ops = &mtk_qspi_ops, - .ofdata_to_platdata = mtk_qspi_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct mtk_qspi_platdata), - .priv_auto_alloc_size = sizeof(struct mtk_qspi_priv), - .probe = mtk_qspi_probe, -};

This patch adds spi-mem driver for MediaTek MT7629 SoC to access SPI-NOR and SPI-NAND flashes.
Cc: Jagan Teki jagan@openedev.com Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- Changes since v1: rename mtk_spimem to spi_snfi_spi. change pinctrl name. Changes since v2: remove udevice in mtk_snfi_priv. Changes since v3: remove check for chipselect. --- drivers/spi/Kconfig | 9 ++ drivers/spi/Makefile | 1 + drivers/spi/mtk_snfi_spi.c | 315 +++++++++++++++++++++++++++++++++++++ 3 files changed, 325 insertions(+) create mode 100644 drivers/spi/mtk_snfi_spi.c
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 95a63065251..11c3015650c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -150,6 +150,15 @@ config MT7621_SPI the SPI NOR flash on platforms embedding this Ralink / MediaTek SPI core, like MT7621/7628/7688.
+config MTK_SNFI_SPI + bool "Mediatek SPI memory controller driver" + depends on SPI_MEM + help + Enable the Mediatek SPI memory controller driver. This driver is + originally based on the MediaTek SNFI IP core. It can only be + used to access SPI memory devices like SPI-NOR or SPI-NAND on + platforms embedding this IP core, like MT7622/M7629. + config MVEBU_A3700_SPI bool "Marvell Armada 3700 SPI driver" select CLK_ARMADA_3720 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index bbec33aa06e..003262953b8 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o +obj-$(CONFIG_MTK_SNFI_SPI) += mtk_snfi_spi.o obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o obj-$(CONFIG_MSCC_BB_SPI) += mscc_bb_spi.o obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o diff --git a/drivers/spi/mtk_snfi_spi.c b/drivers/spi/mtk_snfi_spi.c new file mode 100644 index 00000000000..b6bd7734763 --- /dev/null +++ b/drivers/spi/mtk_snfi_spi.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao weijie.gao@mediatek.com + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <errno.h> +#include <spi.h> +#include <spi-mem.h> +#include <stdbool.h> +#include <dm/pinctrl.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/iopoll.h> + +#define SNFI_MAC_CTL 0x500 +#define MAC_XIO_SEL BIT(4) +#define SF_MAC_EN BIT(3) +#define SF_TRIG BIT(2) +#define WIP_READY BIT(1) +#define WIP BIT(0) + +#define SNFI_MAC_OUTL 0x504 +#define SNFI_MAC_INL 0x508 + +#define SNFI_MISC_CTL 0x538 +#define SW_RST BIT(28) +#define FIFO_RD_LTC_SHIFT 25 +#define FIFO_RD_LTC GENMASK(26, 25) +#define LATCH_LAT_SHIFT 8 +#define LATCH_LAT GENMASK(9, 8) +#define CS_DESELECT_CYC_SHIFT 0 +#define CS_DESELECT_CYC GENMASK(4, 0) + +#define SNF_STA_CTL1 0x550 +#define SPI_STATE GENMASK(3, 0) + +#define SNFI_GPRAM_OFFSET 0x800 +#define SNFI_GPRAM_SIZE 0x80 + +#define SNFI_POLL_INTERVAL 500000 +#define SNFI_RST_POLL_INTERVAL 1000000 + +struct mtk_snfi_priv { + void __iomem *base; + + struct clk nfi_clk; + struct clk pad_clk; +}; + +static int mtk_snfi_adjust_op_size(struct spi_slave *slave, + struct spi_mem_op *op) +{ + u32 nbytes; + + /* + * When there is input data, it will be appended after the output + * data in the GPRAM. So the total size of either pure output data + * or the output+input data must not exceed the GPRAM size. + */ + + nbytes = sizeof(op->cmd.opcode) + op->addr.nbytes + + op->dummy.nbytes; + + if (nbytes + op->data.nbytes <= SNFI_GPRAM_SIZE) + return 0; + + if (nbytes >= SNFI_GPRAM_SIZE) + return -ENOTSUPP; + + op->data.nbytes = SNFI_GPRAM_SIZE - nbytes; + + return 0; +} + +static bool mtk_snfi_supports_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + if (op->cmd.buswidth > 1 || op->addr.buswidth > 1 || + op->dummy.buswidth > 1 || op->data.buswidth > 1) + return false; + + return true; +} + +static int mtk_snfi_mac_trigger(struct mtk_snfi_priv *priv, + struct udevice *bus, u32 outlen, u32 inlen) +{ + int ret; + u32 val; + +#ifdef CONFIG_PINCTRL + pinctrl_select_state(bus, "snfi"); +#endif + + writel(SF_MAC_EN, priv->base + SNFI_MAC_CTL); + writel(outlen, priv->base + SNFI_MAC_OUTL); + writel(inlen, priv->base + SNFI_MAC_INL); + + writel(SF_MAC_EN | SF_TRIG, priv->base + SNFI_MAC_CTL); + + ret = readl_poll_timeout(priv->base + SNFI_MAC_CTL, val, + val & WIP_READY, SNFI_POLL_INTERVAL); + if (ret) { + printf("%s: timed out waiting for WIP_READY\n", __func__); + goto cleanup; + } + + ret = readl_poll_timeout(priv->base + SNFI_MAC_CTL, val, + !(val & WIP), SNFI_POLL_INTERVAL); + if (ret) + printf("%s: timed out waiting for WIP cleared\n", __func__); + + writel(0, priv->base + SNFI_MAC_CTL); + +cleanup: +#ifdef CONFIG_PINCTRL + pinctrl_select_state(bus, "default"); +#endif + + return ret; +} + +static int mtk_snfi_mac_reset(struct mtk_snfi_priv *priv) +{ + int ret; + u32 val; + + setbits_32(priv->base + SNFI_MISC_CTL, SW_RST); + + ret = readl_poll_timeout(priv->base + SNF_STA_CTL1, val, + !(val & SPI_STATE), SNFI_POLL_INTERVAL); + if (ret) + printf("%s: failed to reset snfi mac\n", __func__); + + writel((2 << FIFO_RD_LTC_SHIFT) | + (10 << CS_DESELECT_CYC_SHIFT), + priv->base + SNFI_MISC_CTL); + + return ret; +} + +static void mtk_snfi_copy_to_gpram(struct mtk_snfi_priv *priv, + const void *data, size_t len) +{ + void __iomem *gpram = priv->base + SNFI_GPRAM_OFFSET; + size_t i, n = (len + sizeof(u32) - 1) / sizeof(u32); + const u32 *buff = data; + + /* + * The output data will always be copied to the beginning of + * the GPRAM. Uses word write for better performace. + * + * Trailing bytes in the last word are not cared. + */ + + for (i = 0; i < n; i++) + writel(buff[i], gpram + i * sizeof(u32)); +} + +static void mtk_snfi_copy_from_gpram(struct mtk_snfi_priv *priv, u8 *cache, + void *data, size_t pos, size_t len) +{ + void __iomem *gpram = priv->base + SNFI_GPRAM_OFFSET; + u32 *buff = (u32 *)cache; + size_t i, off, end; + + /* Start position in the buffer */ + off = pos & (sizeof(u32) - 1); + + /* End position for copy */ + end = (len + pos + sizeof(u32) - 1) & (~(sizeof(u32) - 1)); + + /* Start position for copy */ + pos &= ~(sizeof(u32) - 1); + + /* + * Read aligned data from GPRAM to buffer first. + * Uses word read for better performace. + */ + i = 0; + while (pos < end) { + buff[i++] = readl(gpram + pos); + pos += sizeof(u32); + } + + /* Copy rx data */ + memcpy(data, cache + off, len); +} + +static int mtk_snfi_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + struct udevice *bus = dev_get_parent(slave->dev); + struct mtk_snfi_priv *priv = dev_get_priv(bus); + u8 gpram_cache[SNFI_GPRAM_SIZE]; + u32 i, len = 0, inlen = 0; + int addr_sh; + int ret; + + ret = mtk_snfi_mac_reset(priv); + if (ret) + return ret; + + /* Put opcode */ + gpram_cache[len++] = op->cmd.opcode; + + /* Put address */ + addr_sh = (op->addr.nbytes - 1) * 8; + while (addr_sh >= 0) { + gpram_cache[len++] = (op->addr.val >> addr_sh) & 0xff; + addr_sh -= 8; + } + + /* Put dummy bytes */ + for (i = 0; i < op->dummy.nbytes; i++) + gpram_cache[len++] = 0; + + /* Put output data */ + if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) { + memcpy(gpram_cache + len, op->data.buf.out, op->data.nbytes); + len += op->data.nbytes; + } + + /* Copy final output data to GPRAM */ + mtk_snfi_copy_to_gpram(priv, gpram_cache, len); + + /* Start one SPI transaction */ + if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN) + inlen = op->data.nbytes; + + ret = mtk_snfi_mac_trigger(priv, bus, len, inlen); + if (ret) + return ret; + + /* Copy input data from GPRAM */ + if (inlen) + mtk_snfi_copy_from_gpram(priv, gpram_cache, op->data.buf.in, + len, inlen); + + return 0; +} + +static int mtk_snfi_spi_probe(struct udevice *bus) +{ + struct mtk_snfi_priv *priv = dev_get_priv(bus); + int ret; + + priv->base = (void __iomem *)devfdt_get_addr(bus); + if (!priv->base) + return -EINVAL; + + ret = clk_get_by_name(bus, "nfi_clk", &priv->nfi_clk); + if (ret < 0) + return ret; + + ret = clk_get_by_name(bus, "pad_clk", &priv->pad_clk); + if (ret < 0) + return ret; + + clk_enable(&priv->nfi_clk); + clk_enable(&priv->pad_clk); + + return 0; +} + +static int mtk_snfi_set_speed(struct udevice *bus, uint speed) +{ + /* + * The SNFI does not have a bus clock divider. + * The bus clock is set in dts (pad_clk, UNIVPLL2_D8 = 50MHz). + */ + + return 0; +} + +static int mtk_snfi_set_mode(struct udevice *bus, uint mode) +{ + /* The SNFI supports only mode 0 */ + + if (mode) + return -EINVAL; + + return 0; +} + +static const struct spi_controller_mem_ops mtk_snfi_mem_ops = { + .adjust_op_size = mtk_snfi_adjust_op_size, + .supports_op = mtk_snfi_supports_op, + .exec_op = mtk_snfi_exec_op, +}; + +static const struct dm_spi_ops mtk_snfi_spi_ops = { + .mem_ops = &mtk_snfi_mem_ops, + .set_speed = mtk_snfi_set_speed, + .set_mode = mtk_snfi_set_mode, +}; + +static const struct udevice_id mtk_snfi_spi_ids[] = { + { .compatible = "mediatek,mtk-snfi-spi" }, + { } +}; + +U_BOOT_DRIVER(mtk_snfi_spi) = { + .name = "mtk_snfi_spi", + .id = UCLASS_SPI, + .of_match = mtk_snfi_spi_ids, + .ops = &mtk_snfi_spi_ops, + .priv_auto_alloc_size = sizeof(struct mtk_snfi_priv), + .probe = mtk_snfi_spi_probe, +};

The original mtk_qspi driver has been removed. We change MT7629 to use newly added mtk-spimem driver.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- Changes since v1: rename node spimem to snfi. change pinctrl name and order. Changes since v2: none --- arch/arm/dts/mt7629-rfb.dts | 18 +++++++++++++----- arch/arm/dts/mt7629.dtsi | 14 ++++++++++---- 2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/arch/arm/dts/mt7629-rfb.dts b/arch/arm/dts/mt7629-rfb.dts index 4612218a1eb..25f1344817d 100644 --- a/arch/arm/dts/mt7629-rfb.dts +++ b/arch/arm/dts/mt7629-rfb.dts @@ -13,7 +13,7 @@ compatible = "mediatek,mt7629-rfb", "mediatek,mt7629";
aliases { - spi0 = &qspi; + spi0 = &snfi; };
chosen { @@ -34,7 +34,14 @@ };
&pinctrl { - qspi_pins: qspi-pins { + snfi_pins: snfi-pins { + mux { + function = "flash"; + groups = "snfi"; + }; + }; + + snor_pins: snor-pins { mux { function = "flash"; groups = "spi_nor"; @@ -56,9 +63,10 @@ }; };
-&qspi { - pinctrl-names = "default"; - pinctrl-0 = <&qspi_pins>; +&snfi { + pinctrl-names = "default", "snfi"; + pinctrl-0 = <&snor_pins>; + pinctrl-1 = <&snfi_pins>; status = "okay";
spi-flash@0{ diff --git a/arch/arm/dts/mt7629.dtsi b/arch/arm/dts/mt7629.dtsi index c87115e0fe4..135ac8ecfa2 100644 --- a/arch/arm/dts/mt7629.dtsi +++ b/arch/arm/dts/mt7629.dtsi @@ -215,10 +215,16 @@ status = "disabled"; };
- qspi: qspi@11014000 { - compatible = "mediatek,mt7629-qspi"; - reg = <0x11014000 0xe0>, <0x30000000 0x10000000>; - reg-names = "reg_base", "mem_base"; + snfi: snfi@1100d000 { + compatible = "mediatek,mtk-snfi-spi"; + reg = <0x1100d000 0x2000>; + clocks = <&pericfg CLK_PERI_NFI_PD>, + <&pericfg CLK_PERI_SNFI_PD>; + clock-names = "nfi_clk", "pad_clk"; + assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>, + <&topckgen CLK_TOP_NFI_INFRA_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>, + <&topckgen CLK_TOP_UNIVPLL2_D8>; status = "disabled"; #address-cells = <1>; #size-cells = <0>;

This patch replaces MTK_QSPI with MTK_SNFI_SPI to ensure mtk_snfi_spi driver is built by default.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- Changes since v1: none --- configs/mt7629_rfb_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configs/mt7629_rfb_defconfig b/configs/mt7629_rfb_defconfig index 0dceafdaa67..d8efba66201 100644 --- a/configs/mt7629_rfb_defconfig +++ b/configs/mt7629_rfb_defconfig @@ -63,7 +63,7 @@ CONFIG_DM_SERIAL=y CONFIG_MTK_SERIAL=y CONFIG_SPI=y CONFIG_DM_SPI=y -CONFIG_MTK_QSPI=y +CONFIG_MTK_SNFI_SPI=y CONFIG_SYSRESET=y CONFIG_SPL_SYSRESET=y CONFIG_SYSRESET_WATCHDOG=y

Change mtk_qspi.c to mtk_snfi_spi.c
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- Changes since v1: rename mtk_spimem.c to spi_snfi_spi.c Changes since v2: none --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MAINTAINERS b/MAINTAINERS index bea3122f2b6..170395c0079 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -205,7 +205,7 @@ F: drivers/mmc/mtk-sd.c F: drivers/pinctrl/mediatek/ F: drivers/power/domain/mtk-power-domain.c F: drivers/ram/mediatek/ -F: drivers/spi/mtk_qspi.c +F: drivers/spi/mtk_snfi_spi.c F: drivers/timer/mtk_timer.c F: drivers/watchdog/mtk_wdt.c F: drivers/net/mtk_eth.c

On Wed, Jul 10, 2019 at 8:51 AM Weijie Gao weijie.gao@mediatek.com wrote:
Since u-boot has added the spi-mem framework and replaced the spi-nor framework, the mtk_qspi is no longer compatible with the new spi-nor driver.
This patch series add a new spi-mem driver to replace the mtk_qspi driver, with one patch to fix watchdog not feeding during spi operation.
Weijie Gao (6): mtd: spi-nor: add watchdog reset to flash operation loops spi: remove obsolete mtk_qspi driver spi: add spi-mem driver for MediaTek MT7629 SoC arm: dts: change MT7629 to use spi-mem rather than qspi configs: mt7629_rfb: change MTK_QSPI to MTK_SNFI_SPI MAINTAINERS: change spi driver entry
What is v4 change log? I wouldn't find it on individual patches?

On Mon, 2019-07-15 at 12:59 +0530, Jagan Teki wrote:
On Wed, Jul 10, 2019 at 8:51 AM Weijie Gao weijie.gao@mediatek.com wrote:
Since u-boot has added the spi-mem framework and replaced the spi-nor framework, the mtk_qspi is no longer compatible with the new spi-nor driver.
This patch series add a new spi-mem driver to replace the mtk_qspi driver, with one patch to fix watchdog not feeding during spi operation.
Weijie Gao (6): mtd: spi-nor: add watchdog reset to flash operation loops spi: remove obsolete mtk_qspi driver spi: add spi-mem driver for MediaTek MT7629 SoC arm: dts: change MT7629 to use spi-mem rather than qspi configs: mt7629_rfb: change MTK_QSPI to MTK_SNFI_SPI MAINTAINERS: change spi driver entry
What is v4 change log? I wouldn't find it on individual patches?
Oh, I forgot to write this to cover letter. But I have written change log to "spi: add spi-mem driver for MediaTek MT7629 SoC". There is only one change in this patch: remove chip select checking. I think this should be implemented in spi-uclass.

On Tue, Jul 16, 2019 at 7:48 AM Weijie Gao weijie.gao@mediatek.com wrote:
On Mon, 2019-07-15 at 12:59 +0530, Jagan Teki wrote:
On Wed, Jul 10, 2019 at 8:51 AM Weijie Gao weijie.gao@mediatek.com wrote:
Since u-boot has added the spi-mem framework and replaced the spi-nor framework, the mtk_qspi is no longer compatible with the new spi-nor driver.
This patch series add a new spi-mem driver to replace the mtk_qspi driver, with one patch to fix watchdog not feeding during spi operation.
Weijie Gao (6): mtd: spi-nor: add watchdog reset to flash operation loops spi: remove obsolete mtk_qspi driver spi: add spi-mem driver for MediaTek MT7629 SoC arm: dts: change MT7629 to use spi-mem rather than qspi configs: mt7629_rfb: change MTK_QSPI to MTK_SNFI_SPI MAINTAINERS: change spi driver entry
What is v4 change log? I wouldn't find it on individual patches?
Oh, I forgot to write this to cover letter. But I have written change log to "spi: add spi-mem driver for MediaTek MT7629 SoC". There is only one change in this patch: remove chip select checking. I think this should be implemented in spi-uclass.
Okay, np. except 0001 rest look fine for me.
Reviewed-by: Jagan Teki jagan@amarulasolutions.com

On Tue, 2019-07-16 at 17:03 +0530, Jagan Teki wrote:
On Tue, Jul 16, 2019 at 7:48 AM Weijie Gao weijie.gao@mediatek.com wrote:
On Mon, 2019-07-15 at 12:59 +0530, Jagan Teki wrote:
On Wed, Jul 10, 2019 at 8:51 AM Weijie Gao weijie.gao@mediatek.com wrote:
Since u-boot has added the spi-mem framework and replaced the spi-nor framework, the mtk_qspi is no longer compatible with the new spi-nor driver.
This patch series add a new spi-mem driver to replace the mtk_qspi driver, with one patch to fix watchdog not feeding during spi operation.
Weijie Gao (6): mtd: spi-nor: add watchdog reset to flash operation loops spi: remove obsolete mtk_qspi driver spi: add spi-mem driver for MediaTek MT7629 SoC arm: dts: change MT7629 to use spi-mem rather than qspi configs: mt7629_rfb: change MTK_QSPI to MTK_SNFI_SPI MAINTAINERS: change spi driver entry
What is v4 change log? I wouldn't find it on individual patches?
Oh, I forgot to write this to cover letter. But I have written change log to "spi: add spi-mem driver for MediaTek MT7629 SoC". There is only one change in this patch: remove chip select checking. I think this should be implemented in spi-uclass.
Okay, np. except 0001 rest look fine for me.
Reviewed-by: Jagan Teki jagan@amarulasolutions.com
I have tested another solution. I just move WATCHDOG_RESET() into the mtk_snfi_exec_op() so there is no need to modify the spi-nor driver. I think this is better for mt7629.

On Fri, Jul 19, 2019 at 7:47 AM Weijie Gao weijie.gao@mediatek.com wrote:
On Tue, 2019-07-16 at 17:03 +0530, Jagan Teki wrote:
On Tue, Jul 16, 2019 at 7:48 AM Weijie Gao weijie.gao@mediatek.com wrote:
On Mon, 2019-07-15 at 12:59 +0530, Jagan Teki wrote:
On Wed, Jul 10, 2019 at 8:51 AM Weijie Gao weijie.gao@mediatek.com wrote:
Since u-boot has added the spi-mem framework and replaced the spi-nor framework, the mtk_qspi is no longer compatible with the new spi-nor driver.
This patch series add a new spi-mem driver to replace the mtk_qspi driver, with one patch to fix watchdog not feeding during spi operation.
Weijie Gao (6): mtd: spi-nor: add watchdog reset to flash operation loops spi: remove obsolete mtk_qspi driver spi: add spi-mem driver for MediaTek MT7629 SoC arm: dts: change MT7629 to use spi-mem rather than qspi configs: mt7629_rfb: change MTK_QSPI to MTK_SNFI_SPI MAINTAINERS: change spi driver entry
What is v4 change log? I wouldn't find it on individual patches?
Oh, I forgot to write this to cover letter. But I have written change log to "spi: add spi-mem driver for MediaTek MT7629 SoC". There is only one change in this patch: remove chip select checking. I think this should be implemented in spi-uclass.
Okay, np. except 0001 rest look fine for me.
Reviewed-by: Jagan Teki jagan@amarulasolutions.com
I have tested another solution. I just move WATCHDOG_RESET() into the mtk_snfi_exec_op() so there is no need to modify the spi-nor driver. I think this is better for mt7629.
Sounds good.
participants (2)
-
Jagan Teki
-
Weijie Gao