On Tue, 2020-12-08 at 01:48 +0800, Jagan Teki wrote: > On Fri, Nov 13, 2020 at 8:32 AM SkyLake Huang > <skylake.hu...@mediatek.com> wrote: > > > > From: "SkyLake.Huang" <skylake.hu...@mediatek.com> > > > > This patch adds support for MTK SPI NOR controller, which you > > can see on mt7622 & mt7629. > > > > This controller is designed only for SPI NOR. We can't adjust > > its bus clock dynamically. Set clock in dts instead. > > > > Signed-off-by: SkyLake.Huang <skylake.hu...@mediatek.com> > > --- > > drivers/spi/Kconfig | 7 + > > drivers/spi/Makefile | 1 + > > drivers/spi/mtk_snor.c | 597 +++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 605 insertions(+) > > create mode 100644 drivers/spi/mtk_snor.c > > > > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig > > index fae2040af8..670af450c1 100644 > > --- a/drivers/spi/Kconfig > > +++ b/drivers/spi/Kconfig > > @@ -174,6 +174,13 @@ config MT7621_SPI > > the SPI NOR flash on platforms embedding this Ralink / MediaTek > > SPI core, like MT7621/7628/7688. > > > > +config MTK_SNOR > > + bool "Mediatek SPI-NOR controller driver" > > + depends on SPI_MEM > > + help > > + Enable the Mediatek SPINOR controller driver. This driver has > > + better read/write performance with NOR. > > + > > config MTK_SNFI_SPI > > bool "Mediatek SPI memory controller driver" > > depends on SPI_MEM > > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile > > index ae4f2958f8..efe92f6b18 100644 > > --- a/drivers/spi/Makefile > > +++ b/drivers/spi/Makefile > > @@ -38,6 +38,7 @@ 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_MTK_SNOR) += mtk_snor.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_snor.c b/drivers/spi/mtk_snor.c > > new file mode 100644 > > index 0000000000..0a92f1c5a8 > > --- /dev/null > > +++ b/drivers/spi/mtk_snor.c > > @@ -0,0 +1,597 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +// > > +// Mediatek SPI-NOR controller driver > > +// > > +// Copyright (C) 2020 SkyLake Huang <skylake.hu...@mediatek.com> > > +// > > +// Some parts are based on drivers/spi/spi-mtk-nor.c of linux version > > + > > +#include <common.h> > > +#include <clk.h> > > +#include <cpu_func.h> > > +#include <dm.h> > > +#include <errno.h> > > +#include <spi.h> > > +#include <spi-mem.h> > > +#include <stdbool.h> > > +#include <watchdog.h> > > +#include <dm/pinctrl.h> > > +#include <dm/device.h> > > +#include <asm/dma-mapping.h> > > +#include <linux/dma-direction.h> > > +#include <linux/completion.h> > > +#include <linux/bitops.h> > > +#include <linux/io.h> > > +#include <linux/iopoll.h> > > + > > +#define DRIVER_NAME "mtk-spi-nor" > > + > > +#define MTK_NOR_REG_CMD 0x00 > > +#define MTK_NOR_CMD_WRSR BIT(5) > > +#define MTK_NOR_CMD_WRITE BIT(4) > > +#define MTK_NOR_CMD_PROGRAM BIT(2) > > +#define MTK_NOR_CMD_RDSR BIT(1) > > +#define MTK_NOR_CMD_READ BIT(0) > > +#define MTK_NOR_CMD_MASK GENMASK(5, 0) > > + > > +#define MTK_NOR_REG_PRG_CNT 0x04 > > +#define MTK_NOR_REG_RDSR 0x08 > > +#define MTK_NOR_REG_RDATA 0x0c > > + > > +#define MTK_NOR_REG_RADR0 0x10 > > +#define MTK_NOR_REG_RADR(n) (MTK_NOR_REG_RADR0 + 4 * (n)) > > +#define MTK_NOR_REG_RADR3 0xc8 > > + > > +#define MTK_NOR_REG_WDATA 0x1c > > + > > +#define MTK_NOR_REG_PRGDATA0 0x20 > > +#define MTK_NOR_REG_PRGDATA(n) (MTK_NOR_REG_PRGDATA0 + 4 * (n)) > > +#define MTK_NOR_REG_PRGDATA_MAX 5 > > + > > +#define MTK_NOR_REG_SHIFT0 0x38 > > +#define MTK_NOR_REG_SHIFT(n) (MTK_NOR_REG_SHIFT0 + 4 * (n)) > > +#define MTK_NOR_REG_SHIFT_MAX 9 > > + > > +#define MTK_NOR_REG_CFG1 0x60 > > +#define MTK_NOR_FAST_READ BIT(0) > > + > > +#define MTK_NOR_REG_CFG2 0x64 > > +#define MTK_NOR_WR_CUSTOM_OP_EN BIT(4) > > +#define MTK_NOR_WR_BUF_EN BIT(0) > > + > > +#define MTK_NOR_REG_PP_DATA 0x98 > > + > > +#define MTK_NOR_REG_IRQ_STAT 0xa8 > > +#define MTK_NOR_REG_IRQ_EN 0xac > > +#define MTK_NOR_IRQ_DMA BIT(7) > > +#define MTK_NOR_IRQ_WRSR BIT(5) > > +#define MTK_NOR_IRQ_MASK GENMASK(7, 0) > > + > > +#define MTK_NOR_REG_CFG3 0xb4 > > +#define MTK_NOR_DISABLE_WREN BIT(7) > > +#define MTK_NOR_DISABLE_SR_POLL BIT(5) > > + > > +#define MTK_NOR_REG_WP 0xc4 > > +#define MTK_NOR_ENABLE_SF_CMD 0x30 > > + > > +#define MTK_NOR_REG_BUSCFG 0xcc > > +#define MTK_NOR_4B_ADDR BIT(4) > > +#define MTK_NOR_QUAD_ADDR BIT(3) > > +#define MTK_NOR_QUAD_READ BIT(2) > > +#define MTK_NOR_DUAL_ADDR BIT(1) > > +#define MTK_NOR_DUAL_READ BIT(0) > > +#define MTK_NOR_BUS_MODE_MASK GENMASK(4, 0) > > + > > +#define MTK_NOR_REG_DMA_CTL 0x718 > > +#define MTK_NOR_DMA_START BIT(0) > > + > > +#define MTK_NOR_REG_DMA_FADR 0x71c > > +#define MTK_NOR_REG_DMA_DADR 0x720 > > +#define MTK_NOR_REG_DMA_END_DADR 0x724 > > + > > +#define MTK_NOR_PRG_MAX_SIZE 6 > > +// Reading DMA src/dst addresses have to be 16-byte aligned > > +#define MTK_NOR_DMA_ALIGN 16 > > +#define MTK_NOR_DMA_ALIGN_MASK (MTK_NOR_DMA_ALIGN - 1) > > +// and we allocate a bounce buffer if destination address isn't aligned. > > +#define MTK_NOR_BOUNCE_BUF_SIZE PAGE_SIZE > > + > > +// Buffered page program can do one 128-byte transfer > > +#define MTK_NOR_PP_SIZE 128 > > + > > +#define CLK_TO_US(priv, clkcnt) ((clkcnt) * (1000000) / > > ((priv)->spi_freq)) > > + > > +#define MTK_NOR_UNLOCK_ALL 0x0 > > + > > +struct mtk_snor_priv { > > + struct device *dev; > > + void __iomem *base; > > + u8 *buffer; > > + struct clk spi_clk; > > + struct clk ctlr_clk; > > + unsigned int spi_freq; > > + bool wbuf_en; > > +}; > > + > > +static inline dma_addr_t __dma_map_single(void *vaddr, size_t len, > > + enum dma_data_direction dir) > > +{ > > + unsigned long addr = (unsigned long)vaddr; > > + > > + len = ALIGN(len, ARCH_DMA_MINALIGN); > > + if (dir == DMA_FROM_DEVICE) > > + invalidate_dcache_range(addr, addr + len); > > + else > > + flush_dcache_range(addr, addr + len); > > + > > + return addr; > > +} > > + > > +static inline void __dma_unmap_single(dma_addr_t addr, size_t len, > > + enum dma_data_direction dir) > > +{ > > + len = ALIGN(len, ARCH_DMA_MINALIGN); > > + if (dir != DMA_TO_DEVICE) > > + invalidate_dcache_range(addr, addr + len); > > +} > > + > > +static inline void mtk_snor_rmw(struct mtk_snor_priv *priv, u32 reg, u32 > > set, > > + u32 clr) > > +{ > > + u32 val = readl(priv->base + reg); > > + > > + val &= ~clr; > > + val |= set; > > + writel(val, priv->base + reg); > > +} > > + > > +static inline int mtk_snor_cmd_exec(struct mtk_snor_priv *priv, u32 cmd, > > + ulong clk) > > +{ > > + unsigned long long delay = CLK_TO_US(priv, clk); > > + u32 reg; > > + int ret; > > + > > + writel(cmd, priv->base + MTK_NOR_REG_CMD); > > + > > + delay = (delay + 1) * 200; > > + ret = readl_poll_timeout(priv->base + MTK_NOR_REG_CMD, reg, !(reg & > > cmd), > > + delay); > > + if (ret < 0) > > + dev_err(priv->dev, "command %u timeout.\n", cmd); > > + return ret; > > +} > > + > > +static void mtk_snor_set_addr(struct mtk_snor_priv *priv, > > + const struct spi_mem_op *op) > > +{ > > + u32 addr = op->addr.val; > > + int i; > > + > > + for (i = 0; i < 3; i++) { > > + writeb(addr & 0xff, priv->base + MTK_NOR_REG_RADR(i)); > > + addr >>= 8; > > + } > > + if (op->addr.nbytes == 4) { > > + writeb(addr & 0xff, priv->base + MTK_NOR_REG_RADR3); > > + mtk_snor_rmw(priv, MTK_NOR_REG_BUSCFG, MTK_NOR_4B_ADDR, 0); > > + } else { > > + mtk_snor_rmw(priv, MTK_NOR_REG_BUSCFG, 0, MTK_NOR_4B_ADDR); > > + } > > +} > > + > > +static bool mtk_snor_match_read(const struct spi_mem_op *op) > > +{ > > + int dummy = 0; > > + > > + if (op->dummy.buswidth) > > + dummy = op->dummy.nbytes * BITS_PER_BYTE / > > op->dummy.buswidth; > > + > > + if (op->data.buswidth == 2 || op->data.buswidth == 4) { > > + if (op->addr.buswidth == 1) > > + return dummy == 8; > > + else if (op->addr.buswidth == 2) > > + return dummy == 4; > > + else if (op->addr.buswidth == 4) > > + return dummy == 6; > > + } else if ((op->addr.buswidth == 0) && (op->data.buswidth == 1)) { > > + return dummy == 0; > > + } else if ((op->addr.buswidth == 1) && (op->data.buswidth == 1)) { > > + if (op->cmd.opcode == 0x03) > > + return dummy == 0; > > + else if (op->cmd.opcode == 0x0b) > > + return dummy == 8; > > + } > > + return false; > > +} > > This looks like flash command handling on the SPI side. Can you try to > handle this driver at mtd/spi side as UCLASS_SPI_FLASH?
This just double reconfirms whether SPI command is supported by this controller or not. But since the commands issued by mtd/spi layer works fine on this controller (at least single-mode looks good), I think I can remove this function(mtk_snor_match_read). I'll send a v2 patch to correct this.