1d7d9f8ecSStefan Agner // SPDX-License-Identifier: GPL-2.0 2d7d9f8ecSStefan Agner /* 3d7d9f8ecSStefan Agner * Copyright (C) 2018 Stefan Agner <stefan@agner.ch> 4d7d9f8ecSStefan Agner * Copyright (C) 2014-2015 Lucas Stach <dev@lynxeye.de> 5d7d9f8ecSStefan Agner * Copyright (C) 2012 Avionic Design GmbH 6d7d9f8ecSStefan Agner */ 7d7d9f8ecSStefan Agner 8d7d9f8ecSStefan Agner #include <linux/clk.h> 9d7d9f8ecSStefan Agner #include <linux/completion.h> 10d7d9f8ecSStefan Agner #include <linux/dma-mapping.h> 11d7d9f8ecSStefan Agner #include <linux/err.h> 12d7d9f8ecSStefan Agner #include <linux/gpio/consumer.h> 13d7d9f8ecSStefan Agner #include <linux/interrupt.h> 14d7d9f8ecSStefan Agner #include <linux/io.h> 15d7d9f8ecSStefan Agner #include <linux/module.h> 16d7d9f8ecSStefan Agner #include <linux/mtd/partitions.h> 17d7d9f8ecSStefan Agner #include <linux/mtd/rawnand.h> 18d7d9f8ecSStefan Agner #include <linux/of.h> 19d7d9f8ecSStefan Agner #include <linux/platform_device.h> 206902dc2fSDmitry Osipenko #include <linux/pm_runtime.h> 21d7d9f8ecSStefan Agner #include <linux/reset.h> 22d7d9f8ecSStefan Agner 236902dc2fSDmitry Osipenko #include <soc/tegra/common.h> 246902dc2fSDmitry Osipenko 25d7d9f8ecSStefan Agner #define COMMAND 0x00 26d7d9f8ecSStefan Agner #define COMMAND_GO BIT(31) 27d7d9f8ecSStefan Agner #define COMMAND_CLE BIT(30) 28d7d9f8ecSStefan Agner #define COMMAND_ALE BIT(29) 29d7d9f8ecSStefan Agner #define COMMAND_PIO BIT(28) 30d7d9f8ecSStefan Agner #define COMMAND_TX BIT(27) 31d7d9f8ecSStefan Agner #define COMMAND_RX BIT(26) 32d7d9f8ecSStefan Agner #define COMMAND_SEC_CMD BIT(25) 33d7d9f8ecSStefan Agner #define COMMAND_AFT_DAT BIT(24) 34d7d9f8ecSStefan Agner #define COMMAND_TRANS_SIZE(size) ((((size) - 1) & 0xf) << 20) 35d7d9f8ecSStefan Agner #define COMMAND_A_VALID BIT(19) 36d7d9f8ecSStefan Agner #define COMMAND_B_VALID BIT(18) 37d7d9f8ecSStefan Agner #define COMMAND_RD_STATUS_CHK BIT(17) 38d7d9f8ecSStefan Agner #define COMMAND_RBSY_CHK BIT(16) 39d7d9f8ecSStefan Agner #define COMMAND_CE(x) BIT(8 + ((x) & 0x7)) 40d7d9f8ecSStefan Agner #define COMMAND_CLE_SIZE(size) ((((size) - 1) & 0x3) << 4) 41d7d9f8ecSStefan Agner #define COMMAND_ALE_SIZE(size) ((((size) - 1) & 0xf) << 0) 42d7d9f8ecSStefan Agner 43d7d9f8ecSStefan Agner #define STATUS 0x04 44d7d9f8ecSStefan Agner 45d7d9f8ecSStefan Agner #define ISR 0x08 46d7d9f8ecSStefan Agner #define ISR_CORRFAIL_ERR BIT(24) 47d7d9f8ecSStefan Agner #define ISR_UND BIT(7) 48d7d9f8ecSStefan Agner #define ISR_OVR BIT(6) 49d7d9f8ecSStefan Agner #define ISR_CMD_DONE BIT(5) 50d7d9f8ecSStefan Agner #define ISR_ECC_ERR BIT(4) 51d7d9f8ecSStefan Agner 52d7d9f8ecSStefan Agner #define IER 0x0c 53d7d9f8ecSStefan Agner #define IER_ERR_TRIG_VAL(x) (((x) & 0xf) << 16) 54d7d9f8ecSStefan Agner #define IER_UND BIT(7) 55d7d9f8ecSStefan Agner #define IER_OVR BIT(6) 56d7d9f8ecSStefan Agner #define IER_CMD_DONE BIT(5) 57d7d9f8ecSStefan Agner #define IER_ECC_ERR BIT(4) 58d7d9f8ecSStefan Agner #define IER_GIE BIT(0) 59d7d9f8ecSStefan Agner 60d7d9f8ecSStefan Agner #define CONFIG 0x10 61d7d9f8ecSStefan Agner #define CONFIG_HW_ECC BIT(31) 62d7d9f8ecSStefan Agner #define CONFIG_ECC_SEL BIT(30) 63d7d9f8ecSStefan Agner #define CONFIG_ERR_COR BIT(29) 64d7d9f8ecSStefan Agner #define CONFIG_PIPE_EN BIT(28) 65d7d9f8ecSStefan Agner #define CONFIG_TVAL_4 (0 << 24) 66d7d9f8ecSStefan Agner #define CONFIG_TVAL_6 (1 << 24) 67d7d9f8ecSStefan Agner #define CONFIG_TVAL_8 (2 << 24) 68d7d9f8ecSStefan Agner #define CONFIG_SKIP_SPARE BIT(23) 69d7d9f8ecSStefan Agner #define CONFIG_BUS_WIDTH_16 BIT(21) 70d7d9f8ecSStefan Agner #define CONFIG_COM_BSY BIT(20) 71d7d9f8ecSStefan Agner #define CONFIG_PS_256 (0 << 16) 72d7d9f8ecSStefan Agner #define CONFIG_PS_512 (1 << 16) 73d7d9f8ecSStefan Agner #define CONFIG_PS_1024 (2 << 16) 74d7d9f8ecSStefan Agner #define CONFIG_PS_2048 (3 << 16) 75d7d9f8ecSStefan Agner #define CONFIG_PS_4096 (4 << 16) 76d7d9f8ecSStefan Agner #define CONFIG_SKIP_SPARE_SIZE_4 (0 << 14) 77d7d9f8ecSStefan Agner #define CONFIG_SKIP_SPARE_SIZE_8 (1 << 14) 78d7d9f8ecSStefan Agner #define CONFIG_SKIP_SPARE_SIZE_12 (2 << 14) 79d7d9f8ecSStefan Agner #define CONFIG_SKIP_SPARE_SIZE_16 (3 << 14) 80d7d9f8ecSStefan Agner #define CONFIG_TAG_BYTE_SIZE(x) ((x) & 0xff) 81d7d9f8ecSStefan Agner 82d7d9f8ecSStefan Agner #define TIMING_1 0x14 83d7d9f8ecSStefan Agner #define TIMING_TRP_RESP(x) (((x) & 0xf) << 28) 84d7d9f8ecSStefan Agner #define TIMING_TWB(x) (((x) & 0xf) << 24) 85d7d9f8ecSStefan Agner #define TIMING_TCR_TAR_TRR(x) (((x) & 0xf) << 20) 86d7d9f8ecSStefan Agner #define TIMING_TWHR(x) (((x) & 0xf) << 16) 87d7d9f8ecSStefan Agner #define TIMING_TCS(x) (((x) & 0x3) << 14) 88d7d9f8ecSStefan Agner #define TIMING_TWH(x) (((x) & 0x3) << 12) 89d7d9f8ecSStefan Agner #define TIMING_TWP(x) (((x) & 0xf) << 8) 90d7d9f8ecSStefan Agner #define TIMING_TRH(x) (((x) & 0x3) << 4) 91d7d9f8ecSStefan Agner #define TIMING_TRP(x) (((x) & 0xf) << 0) 92d7d9f8ecSStefan Agner 93d7d9f8ecSStefan Agner #define RESP 0x18 94d7d9f8ecSStefan Agner 95d7d9f8ecSStefan Agner #define TIMING_2 0x1c 96d7d9f8ecSStefan Agner #define TIMING_TADL(x) ((x) & 0xf) 97d7d9f8ecSStefan Agner 98d7d9f8ecSStefan Agner #define CMD_REG1 0x20 99d7d9f8ecSStefan Agner #define CMD_REG2 0x24 100d7d9f8ecSStefan Agner #define ADDR_REG1 0x28 101d7d9f8ecSStefan Agner #define ADDR_REG2 0x2c 102d7d9f8ecSStefan Agner 103d7d9f8ecSStefan Agner #define DMA_MST_CTRL 0x30 104d7d9f8ecSStefan Agner #define DMA_MST_CTRL_GO BIT(31) 105d7d9f8ecSStefan Agner #define DMA_MST_CTRL_IN (0 << 30) 106d7d9f8ecSStefan Agner #define DMA_MST_CTRL_OUT BIT(30) 107d7d9f8ecSStefan Agner #define DMA_MST_CTRL_PERF_EN BIT(29) 108d7d9f8ecSStefan Agner #define DMA_MST_CTRL_IE_DONE BIT(28) 109d7d9f8ecSStefan Agner #define DMA_MST_CTRL_REUSE BIT(27) 110d7d9f8ecSStefan Agner #define DMA_MST_CTRL_BURST_1 (2 << 24) 111d7d9f8ecSStefan Agner #define DMA_MST_CTRL_BURST_4 (3 << 24) 112d7d9f8ecSStefan Agner #define DMA_MST_CTRL_BURST_8 (4 << 24) 113d7d9f8ecSStefan Agner #define DMA_MST_CTRL_BURST_16 (5 << 24) 114d7d9f8ecSStefan Agner #define DMA_MST_CTRL_IS_DONE BIT(20) 115d7d9f8ecSStefan Agner #define DMA_MST_CTRL_EN_A BIT(2) 116d7d9f8ecSStefan Agner #define DMA_MST_CTRL_EN_B BIT(1) 117d7d9f8ecSStefan Agner 118d7d9f8ecSStefan Agner #define DMA_CFG_A 0x34 119d7d9f8ecSStefan Agner #define DMA_CFG_B 0x38 120d7d9f8ecSStefan Agner 121d7d9f8ecSStefan Agner #define FIFO_CTRL 0x3c 122d7d9f8ecSStefan Agner #define FIFO_CTRL_CLR_ALL BIT(3) 123d7d9f8ecSStefan Agner 124d7d9f8ecSStefan Agner #define DATA_PTR 0x40 125d7d9f8ecSStefan Agner #define TAG_PTR 0x44 126d7d9f8ecSStefan Agner #define ECC_PTR 0x48 127d7d9f8ecSStefan Agner 128d7d9f8ecSStefan Agner #define DEC_STATUS 0x4c 129d7d9f8ecSStefan Agner #define DEC_STATUS_A_ECC_FAIL BIT(1) 130d7d9f8ecSStefan Agner #define DEC_STATUS_ERR_COUNT_MASK 0x00ff0000 131d7d9f8ecSStefan Agner #define DEC_STATUS_ERR_COUNT_SHIFT 16 132d7d9f8ecSStefan Agner 133d7d9f8ecSStefan Agner #define HWSTATUS_CMD 0x50 134d7d9f8ecSStefan Agner #define HWSTATUS_MASK 0x54 135d7d9f8ecSStefan Agner #define HWSTATUS_RDSTATUS_MASK(x) (((x) & 0xff) << 24) 136d7d9f8ecSStefan Agner #define HWSTATUS_RDSTATUS_VALUE(x) (((x) & 0xff) << 16) 137d7d9f8ecSStefan Agner #define HWSTATUS_RBSY_MASK(x) (((x) & 0xff) << 8) 138d7d9f8ecSStefan Agner #define HWSTATUS_RBSY_VALUE(x) (((x) & 0xff) << 0) 139d7d9f8ecSStefan Agner 140d7d9f8ecSStefan Agner #define BCH_CONFIG 0xcc 141d7d9f8ecSStefan Agner #define BCH_ENABLE BIT(0) 142d7d9f8ecSStefan Agner #define BCH_TVAL_4 (0 << 4) 143d7d9f8ecSStefan Agner #define BCH_TVAL_8 (1 << 4) 144d7d9f8ecSStefan Agner #define BCH_TVAL_14 (2 << 4) 145d7d9f8ecSStefan Agner #define BCH_TVAL_16 (3 << 4) 146d7d9f8ecSStefan Agner 147d7d9f8ecSStefan Agner #define DEC_STAT_RESULT 0xd0 148d7d9f8ecSStefan Agner #define DEC_STAT_BUF 0xd4 149d7d9f8ecSStefan Agner #define DEC_STAT_BUF_FAIL_SEC_FLAG_MASK 0xff000000 150d7d9f8ecSStefan Agner #define DEC_STAT_BUF_FAIL_SEC_FLAG_SHIFT 24 151d7d9f8ecSStefan Agner #define DEC_STAT_BUF_CORR_SEC_FLAG_MASK 0x00ff0000 152d7d9f8ecSStefan Agner #define DEC_STAT_BUF_CORR_SEC_FLAG_SHIFT 16 153d7d9f8ecSStefan Agner #define DEC_STAT_BUF_MAX_CORR_CNT_MASK 0x00001f00 154d7d9f8ecSStefan Agner #define DEC_STAT_BUF_MAX_CORR_CNT_SHIFT 8 155d7d9f8ecSStefan Agner 156d7d9f8ecSStefan Agner #define OFFSET(val, off) ((val) < (off) ? 0 : (val) - (off)) 157d7d9f8ecSStefan Agner 158d7d9f8ecSStefan Agner #define SKIP_SPARE_BYTES 4 159d7d9f8ecSStefan Agner #define BITS_PER_STEP_RS 18 160d7d9f8ecSStefan Agner #define BITS_PER_STEP_BCH 13 161d7d9f8ecSStefan Agner 162d7d9f8ecSStefan Agner #define INT_MASK (IER_UND | IER_OVR | IER_CMD_DONE | IER_GIE) 163d7d9f8ecSStefan Agner #define HWSTATUS_CMD_DEFAULT NAND_STATUS_READY 164d7d9f8ecSStefan Agner #define HWSTATUS_MASK_DEFAULT (HWSTATUS_RDSTATUS_MASK(1) | \ 165d7d9f8ecSStefan Agner HWSTATUS_RDSTATUS_VALUE(0) | \ 166d7d9f8ecSStefan Agner HWSTATUS_RBSY_MASK(NAND_STATUS_READY) | \ 167d7d9f8ecSStefan Agner HWSTATUS_RBSY_VALUE(NAND_STATUS_READY)) 168d7d9f8ecSStefan Agner 169d7d9f8ecSStefan Agner struct tegra_nand_controller { 1707da45139SMiquel Raynal struct nand_controller controller; 171d7d9f8ecSStefan Agner struct device *dev; 172d7d9f8ecSStefan Agner void __iomem *regs; 173d7d9f8ecSStefan Agner int irq; 174d7d9f8ecSStefan Agner struct clk *clk; 175d7d9f8ecSStefan Agner struct completion command_complete; 176d7d9f8ecSStefan Agner struct completion dma_complete; 177d7d9f8ecSStefan Agner bool last_read_error; 178d7d9f8ecSStefan Agner int cur_cs; 179d7d9f8ecSStefan Agner struct nand_chip *chip; 180d7d9f8ecSStefan Agner }; 181d7d9f8ecSStefan Agner 182d7d9f8ecSStefan Agner struct tegra_nand_chip { 183d7d9f8ecSStefan Agner struct nand_chip chip; 184d7d9f8ecSStefan Agner struct gpio_desc *wp_gpio; 185d7d9f8ecSStefan Agner struct mtd_oob_region ecc; 186d7d9f8ecSStefan Agner u32 config; 187d7d9f8ecSStefan Agner u32 config_ecc; 188d7d9f8ecSStefan Agner u32 bch_config; 189d7d9f8ecSStefan Agner int cs[1]; 190d7d9f8ecSStefan Agner }; 191d7d9f8ecSStefan Agner 192d7d9f8ecSStefan Agner static inline struct tegra_nand_controller * 1937da45139SMiquel Raynal to_tegra_ctrl(struct nand_controller *hw_ctrl) 194d7d9f8ecSStefan Agner { 195d7d9f8ecSStefan Agner return container_of(hw_ctrl, struct tegra_nand_controller, controller); 196d7d9f8ecSStefan Agner } 197d7d9f8ecSStefan Agner 198d7d9f8ecSStefan Agner static inline struct tegra_nand_chip *to_tegra_chip(struct nand_chip *chip) 199d7d9f8ecSStefan Agner { 200d7d9f8ecSStefan Agner return container_of(chip, struct tegra_nand_chip, chip); 201d7d9f8ecSStefan Agner } 202d7d9f8ecSStefan Agner 203d7d9f8ecSStefan Agner static int tegra_nand_ooblayout_rs_ecc(struct mtd_info *mtd, int section, 204d7d9f8ecSStefan Agner struct mtd_oob_region *oobregion) 205d7d9f8ecSStefan Agner { 206d7d9f8ecSStefan Agner struct nand_chip *chip = mtd_to_nand(mtd); 207d7d9f8ecSStefan Agner int bytes_per_step = DIV_ROUND_UP(BITS_PER_STEP_RS * chip->ecc.strength, 208d7d9f8ecSStefan Agner BITS_PER_BYTE); 209d7d9f8ecSStefan Agner 210d7d9f8ecSStefan Agner if (section > 0) 211d7d9f8ecSStefan Agner return -ERANGE; 212d7d9f8ecSStefan Agner 213d7d9f8ecSStefan Agner oobregion->offset = SKIP_SPARE_BYTES; 214d7d9f8ecSStefan Agner oobregion->length = round_up(bytes_per_step * chip->ecc.steps, 4); 215d7d9f8ecSStefan Agner 216d7d9f8ecSStefan Agner return 0; 217d7d9f8ecSStefan Agner } 218d7d9f8ecSStefan Agner 219d7d9f8ecSStefan Agner static int tegra_nand_ooblayout_no_free(struct mtd_info *mtd, int section, 220d7d9f8ecSStefan Agner struct mtd_oob_region *oobregion) 221d7d9f8ecSStefan Agner { 222d7d9f8ecSStefan Agner return -ERANGE; 223d7d9f8ecSStefan Agner } 224d7d9f8ecSStefan Agner 225d7d9f8ecSStefan Agner static const struct mtd_ooblayout_ops tegra_nand_oob_rs_ops = { 226d7d9f8ecSStefan Agner .ecc = tegra_nand_ooblayout_rs_ecc, 227d7d9f8ecSStefan Agner .free = tegra_nand_ooblayout_no_free, 228d7d9f8ecSStefan Agner }; 229d7d9f8ecSStefan Agner 230d7d9f8ecSStefan Agner static int tegra_nand_ooblayout_bch_ecc(struct mtd_info *mtd, int section, 231d7d9f8ecSStefan Agner struct mtd_oob_region *oobregion) 232d7d9f8ecSStefan Agner { 233d7d9f8ecSStefan Agner struct nand_chip *chip = mtd_to_nand(mtd); 234d7d9f8ecSStefan Agner int bytes_per_step = DIV_ROUND_UP(BITS_PER_STEP_BCH * chip->ecc.strength, 235d7d9f8ecSStefan Agner BITS_PER_BYTE); 236d7d9f8ecSStefan Agner 237d7d9f8ecSStefan Agner if (section > 0) 238d7d9f8ecSStefan Agner return -ERANGE; 239d7d9f8ecSStefan Agner 240d7d9f8ecSStefan Agner oobregion->offset = SKIP_SPARE_BYTES; 241d7d9f8ecSStefan Agner oobregion->length = round_up(bytes_per_step * chip->ecc.steps, 4); 242d7d9f8ecSStefan Agner 243d7d9f8ecSStefan Agner return 0; 244d7d9f8ecSStefan Agner } 245d7d9f8ecSStefan Agner 246d7d9f8ecSStefan Agner static const struct mtd_ooblayout_ops tegra_nand_oob_bch_ops = { 247d7d9f8ecSStefan Agner .ecc = tegra_nand_ooblayout_bch_ecc, 248d7d9f8ecSStefan Agner .free = tegra_nand_ooblayout_no_free, 249d7d9f8ecSStefan Agner }; 250d7d9f8ecSStefan Agner 251d7d9f8ecSStefan Agner static irqreturn_t tegra_nand_irq(int irq, void *data) 252d7d9f8ecSStefan Agner { 253d7d9f8ecSStefan Agner struct tegra_nand_controller *ctrl = data; 254d7d9f8ecSStefan Agner u32 isr, dma; 255d7d9f8ecSStefan Agner 256d7d9f8ecSStefan Agner isr = readl_relaxed(ctrl->regs + ISR); 257d7d9f8ecSStefan Agner dma = readl_relaxed(ctrl->regs + DMA_MST_CTRL); 258d7d9f8ecSStefan Agner dev_dbg(ctrl->dev, "isr %08x\n", isr); 259d7d9f8ecSStefan Agner 260d7d9f8ecSStefan Agner if (!isr && !(dma & DMA_MST_CTRL_IS_DONE)) 261d7d9f8ecSStefan Agner return IRQ_NONE; 262d7d9f8ecSStefan Agner 263d7d9f8ecSStefan Agner /* 264d7d9f8ecSStefan Agner * The bit name is somewhat missleading: This is also set when 265d7d9f8ecSStefan Agner * HW ECC was successful. The data sheet states: 266d7d9f8ecSStefan Agner * Correctable OR Un-correctable errors occurred in the DMA transfer... 267d7d9f8ecSStefan Agner */ 268d7d9f8ecSStefan Agner if (isr & ISR_CORRFAIL_ERR) 269d7d9f8ecSStefan Agner ctrl->last_read_error = true; 270d7d9f8ecSStefan Agner 271d7d9f8ecSStefan Agner if (isr & ISR_CMD_DONE) 272d7d9f8ecSStefan Agner complete(&ctrl->command_complete); 273d7d9f8ecSStefan Agner 274d7d9f8ecSStefan Agner if (isr & ISR_UND) 275d7d9f8ecSStefan Agner dev_err(ctrl->dev, "FIFO underrun\n"); 276d7d9f8ecSStefan Agner 277d7d9f8ecSStefan Agner if (isr & ISR_OVR) 278d7d9f8ecSStefan Agner dev_err(ctrl->dev, "FIFO overrun\n"); 279d7d9f8ecSStefan Agner 280d7d9f8ecSStefan Agner /* handle DMA interrupts */ 281d7d9f8ecSStefan Agner if (dma & DMA_MST_CTRL_IS_DONE) { 282d7d9f8ecSStefan Agner writel_relaxed(dma, ctrl->regs + DMA_MST_CTRL); 283d7d9f8ecSStefan Agner complete(&ctrl->dma_complete); 284d7d9f8ecSStefan Agner } 285d7d9f8ecSStefan Agner 286d7d9f8ecSStefan Agner /* clear interrupts */ 287d7d9f8ecSStefan Agner writel_relaxed(isr, ctrl->regs + ISR); 288d7d9f8ecSStefan Agner 289d7d9f8ecSStefan Agner return IRQ_HANDLED; 290d7d9f8ecSStefan Agner } 291d7d9f8ecSStefan Agner 292d7d9f8ecSStefan Agner static const char * const tegra_nand_reg_names[] = { 293d7d9f8ecSStefan Agner "COMMAND", 294d7d9f8ecSStefan Agner "STATUS", 295d7d9f8ecSStefan Agner "ISR", 296d7d9f8ecSStefan Agner "IER", 297d7d9f8ecSStefan Agner "CONFIG", 298d7d9f8ecSStefan Agner "TIMING", 299d7d9f8ecSStefan Agner NULL, 300d7d9f8ecSStefan Agner "TIMING2", 301d7d9f8ecSStefan Agner "CMD_REG1", 302d7d9f8ecSStefan Agner "CMD_REG2", 303d7d9f8ecSStefan Agner "ADDR_REG1", 304d7d9f8ecSStefan Agner "ADDR_REG2", 305d7d9f8ecSStefan Agner "DMA_MST_CTRL", 306d7d9f8ecSStefan Agner "DMA_CFG_A", 307d7d9f8ecSStefan Agner "DMA_CFG_B", 308d7d9f8ecSStefan Agner "FIFO_CTRL", 309d7d9f8ecSStefan Agner }; 310d7d9f8ecSStefan Agner 311d7d9f8ecSStefan Agner static void tegra_nand_dump_reg(struct tegra_nand_controller *ctrl) 312d7d9f8ecSStefan Agner { 313d7d9f8ecSStefan Agner u32 reg; 314d7d9f8ecSStefan Agner int i; 315d7d9f8ecSStefan Agner 316d7d9f8ecSStefan Agner dev_err(ctrl->dev, "Tegra NAND controller register dump\n"); 317d7d9f8ecSStefan Agner for (i = 0; i < ARRAY_SIZE(tegra_nand_reg_names); i++) { 318d7d9f8ecSStefan Agner const char *reg_name = tegra_nand_reg_names[i]; 319d7d9f8ecSStefan Agner 320d7d9f8ecSStefan Agner if (!reg_name) 321d7d9f8ecSStefan Agner continue; 322d7d9f8ecSStefan Agner 323d7d9f8ecSStefan Agner reg = readl_relaxed(ctrl->regs + (i * 4)); 324d7d9f8ecSStefan Agner dev_err(ctrl->dev, "%s: 0x%08x\n", reg_name, reg); 325d7d9f8ecSStefan Agner } 326d7d9f8ecSStefan Agner } 327d7d9f8ecSStefan Agner 328d7d9f8ecSStefan Agner static void tegra_nand_controller_abort(struct tegra_nand_controller *ctrl) 329d7d9f8ecSStefan Agner { 330d7d9f8ecSStefan Agner u32 isr, dma; 331d7d9f8ecSStefan Agner 332d7d9f8ecSStefan Agner disable_irq(ctrl->irq); 333d7d9f8ecSStefan Agner 334d7d9f8ecSStefan Agner /* Abort current command/DMA operation */ 335d7d9f8ecSStefan Agner writel_relaxed(0, ctrl->regs + DMA_MST_CTRL); 336d7d9f8ecSStefan Agner writel_relaxed(0, ctrl->regs + COMMAND); 337d7d9f8ecSStefan Agner 338d7d9f8ecSStefan Agner /* clear interrupts */ 339d7d9f8ecSStefan Agner isr = readl_relaxed(ctrl->regs + ISR); 340d7d9f8ecSStefan Agner writel_relaxed(isr, ctrl->regs + ISR); 341d7d9f8ecSStefan Agner dma = readl_relaxed(ctrl->regs + DMA_MST_CTRL); 342d7d9f8ecSStefan Agner writel_relaxed(dma, ctrl->regs + DMA_MST_CTRL); 343d7d9f8ecSStefan Agner 344d7d9f8ecSStefan Agner reinit_completion(&ctrl->command_complete); 345d7d9f8ecSStefan Agner reinit_completion(&ctrl->dma_complete); 346d7d9f8ecSStefan Agner 347d7d9f8ecSStefan Agner enable_irq(ctrl->irq); 348d7d9f8ecSStefan Agner } 349d7d9f8ecSStefan Agner 350d7d9f8ecSStefan Agner static int tegra_nand_cmd(struct nand_chip *chip, 351d7d9f8ecSStefan Agner const struct nand_subop *subop) 352d7d9f8ecSStefan Agner { 353d7d9f8ecSStefan Agner const struct nand_op_instr *instr; 354d7d9f8ecSStefan Agner const struct nand_op_instr *instr_data_in = NULL; 355d7d9f8ecSStefan Agner struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); 356d7d9f8ecSStefan Agner unsigned int op_id, size = 0, offset = 0; 357d7d9f8ecSStefan Agner bool first_cmd = true; 358d7d9f8ecSStefan Agner u32 reg, cmd = 0; 359d7d9f8ecSStefan Agner int ret; 360d7d9f8ecSStefan Agner 361d7d9f8ecSStefan Agner for (op_id = 0; op_id < subop->ninstrs; op_id++) { 362d7d9f8ecSStefan Agner unsigned int naddrs, i; 363d7d9f8ecSStefan Agner const u8 *addrs; 364d7d9f8ecSStefan Agner u32 addr1 = 0, addr2 = 0; 365d7d9f8ecSStefan Agner 366d7d9f8ecSStefan Agner instr = &subop->instrs[op_id]; 367d7d9f8ecSStefan Agner 368d7d9f8ecSStefan Agner switch (instr->type) { 369d7d9f8ecSStefan Agner case NAND_OP_CMD_INSTR: 370d7d9f8ecSStefan Agner if (first_cmd) { 371d7d9f8ecSStefan Agner cmd |= COMMAND_CLE; 372d7d9f8ecSStefan Agner writel_relaxed(instr->ctx.cmd.opcode, 373d7d9f8ecSStefan Agner ctrl->regs + CMD_REG1); 374d7d9f8ecSStefan Agner } else { 375d7d9f8ecSStefan Agner cmd |= COMMAND_SEC_CMD; 376d7d9f8ecSStefan Agner writel_relaxed(instr->ctx.cmd.opcode, 377d7d9f8ecSStefan Agner ctrl->regs + CMD_REG2); 378d7d9f8ecSStefan Agner } 379d7d9f8ecSStefan Agner first_cmd = false; 380d7d9f8ecSStefan Agner break; 381d7d9f8ecSStefan Agner 382d7d9f8ecSStefan Agner case NAND_OP_ADDR_INSTR: 383d7d9f8ecSStefan Agner offset = nand_subop_get_addr_start_off(subop, op_id); 384d7d9f8ecSStefan Agner naddrs = nand_subop_get_num_addr_cyc(subop, op_id); 385d7d9f8ecSStefan Agner addrs = &instr->ctx.addr.addrs[offset]; 386d7d9f8ecSStefan Agner 387d7d9f8ecSStefan Agner cmd |= COMMAND_ALE | COMMAND_ALE_SIZE(naddrs); 388d7d9f8ecSStefan Agner for (i = 0; i < min_t(unsigned int, 4, naddrs); i++) 389d7d9f8ecSStefan Agner addr1 |= *addrs++ << (BITS_PER_BYTE * i); 390d7d9f8ecSStefan Agner naddrs -= i; 391d7d9f8ecSStefan Agner for (i = 0; i < min_t(unsigned int, 4, naddrs); i++) 392d7d9f8ecSStefan Agner addr2 |= *addrs++ << (BITS_PER_BYTE * i); 393d7d9f8ecSStefan Agner 394d7d9f8ecSStefan Agner writel_relaxed(addr1, ctrl->regs + ADDR_REG1); 395d7d9f8ecSStefan Agner writel_relaxed(addr2, ctrl->regs + ADDR_REG2); 396d7d9f8ecSStefan Agner break; 397d7d9f8ecSStefan Agner 398d7d9f8ecSStefan Agner case NAND_OP_DATA_IN_INSTR: 399d7d9f8ecSStefan Agner size = nand_subop_get_data_len(subop, op_id); 400d7d9f8ecSStefan Agner offset = nand_subop_get_data_start_off(subop, op_id); 401d7d9f8ecSStefan Agner 402d7d9f8ecSStefan Agner cmd |= COMMAND_TRANS_SIZE(size) | COMMAND_PIO | 403d7d9f8ecSStefan Agner COMMAND_RX | COMMAND_A_VALID; 404d7d9f8ecSStefan Agner 405d7d9f8ecSStefan Agner instr_data_in = instr; 406d7d9f8ecSStefan Agner break; 407d7d9f8ecSStefan Agner 408d7d9f8ecSStefan Agner case NAND_OP_DATA_OUT_INSTR: 409d7d9f8ecSStefan Agner size = nand_subop_get_data_len(subop, op_id); 410d7d9f8ecSStefan Agner offset = nand_subop_get_data_start_off(subop, op_id); 411d7d9f8ecSStefan Agner 412d7d9f8ecSStefan Agner cmd |= COMMAND_TRANS_SIZE(size) | COMMAND_PIO | 413d7d9f8ecSStefan Agner COMMAND_TX | COMMAND_A_VALID; 414d7d9f8ecSStefan Agner memcpy(®, instr->ctx.data.buf.out + offset, size); 415d7d9f8ecSStefan Agner 416d7d9f8ecSStefan Agner writel_relaxed(reg, ctrl->regs + RESP); 417d7d9f8ecSStefan Agner break; 418d7d9f8ecSStefan Agner 419d7d9f8ecSStefan Agner case NAND_OP_WAITRDY_INSTR: 420d7d9f8ecSStefan Agner cmd |= COMMAND_RBSY_CHK; 421d7d9f8ecSStefan Agner break; 422d7d9f8ecSStefan Agner } 423d7d9f8ecSStefan Agner } 424d7d9f8ecSStefan Agner 425d7d9f8ecSStefan Agner cmd |= COMMAND_GO | COMMAND_CE(ctrl->cur_cs); 426d7d9f8ecSStefan Agner writel_relaxed(cmd, ctrl->regs + COMMAND); 427d7d9f8ecSStefan Agner ret = wait_for_completion_timeout(&ctrl->command_complete, 428d7d9f8ecSStefan Agner msecs_to_jiffies(500)); 429d7d9f8ecSStefan Agner if (!ret) { 430d7d9f8ecSStefan Agner dev_err(ctrl->dev, "COMMAND timeout\n"); 431d7d9f8ecSStefan Agner tegra_nand_dump_reg(ctrl); 432d7d9f8ecSStefan Agner tegra_nand_controller_abort(ctrl); 433d7d9f8ecSStefan Agner return -ETIMEDOUT; 434d7d9f8ecSStefan Agner } 435d7d9f8ecSStefan Agner 436d7d9f8ecSStefan Agner if (instr_data_in) { 437d7d9f8ecSStefan Agner reg = readl_relaxed(ctrl->regs + RESP); 438d7d9f8ecSStefan Agner memcpy(instr_data_in->ctx.data.buf.in + offset, ®, size); 439d7d9f8ecSStefan Agner } 440d7d9f8ecSStefan Agner 441d7d9f8ecSStefan Agner return 0; 442d7d9f8ecSStefan Agner } 443d7d9f8ecSStefan Agner 444d7d9f8ecSStefan Agner static const struct nand_op_parser tegra_nand_op_parser = NAND_OP_PARSER( 445d7d9f8ecSStefan Agner NAND_OP_PARSER_PATTERN(tegra_nand_cmd, 446d7d9f8ecSStefan Agner NAND_OP_PARSER_PAT_CMD_ELEM(true), 447d7d9f8ecSStefan Agner NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8), 448d7d9f8ecSStefan Agner NAND_OP_PARSER_PAT_CMD_ELEM(true), 449d7d9f8ecSStefan Agner NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)), 450d7d9f8ecSStefan Agner NAND_OP_PARSER_PATTERN(tegra_nand_cmd, 451d7d9f8ecSStefan Agner NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 4)), 452d7d9f8ecSStefan Agner NAND_OP_PARSER_PATTERN(tegra_nand_cmd, 453d7d9f8ecSStefan Agner NAND_OP_PARSER_PAT_CMD_ELEM(true), 454d7d9f8ecSStefan Agner NAND_OP_PARSER_PAT_ADDR_ELEM(true, 8), 455d7d9f8ecSStefan Agner NAND_OP_PARSER_PAT_CMD_ELEM(true), 456d7d9f8ecSStefan Agner NAND_OP_PARSER_PAT_WAITRDY_ELEM(true), 457d7d9f8ecSStefan Agner NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 4)), 458d7d9f8ecSStefan Agner ); 459d7d9f8ecSStefan Agner 4602ace451cSBoris Brezillon static void tegra_nand_select_target(struct nand_chip *chip, 4612ace451cSBoris Brezillon unsigned int die_nr) 462d7d9f8ecSStefan Agner { 463d7d9f8ecSStefan Agner struct tegra_nand_chip *nand = to_tegra_chip(chip); 464d7d9f8ecSStefan Agner struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); 465d7d9f8ecSStefan Agner 4662ace451cSBoris Brezillon ctrl->cur_cs = nand->cs[die_nr]; 467d7d9f8ecSStefan Agner } 468d7d9f8ecSStefan Agner 4692ace451cSBoris Brezillon static int tegra_nand_exec_op(struct nand_chip *chip, 4702ace451cSBoris Brezillon const struct nand_operation *op, 4712ace451cSBoris Brezillon bool check_only) 4722ace451cSBoris Brezillon { 473ce446b4bSBoris Brezillon if (!check_only) 4742ace451cSBoris Brezillon tegra_nand_select_target(chip, op->cs); 475ce446b4bSBoris Brezillon 4762ace451cSBoris Brezillon return nand_op_parser_exec_op(chip, &tegra_nand_op_parser, op, 4772ace451cSBoris Brezillon check_only); 478d7d9f8ecSStefan Agner } 479d7d9f8ecSStefan Agner 480d7d9f8ecSStefan Agner static void tegra_nand_hw_ecc(struct tegra_nand_controller *ctrl, 481d7d9f8ecSStefan Agner struct nand_chip *chip, bool enable) 482d7d9f8ecSStefan Agner { 483d7d9f8ecSStefan Agner struct tegra_nand_chip *nand = to_tegra_chip(chip); 484d7d9f8ecSStefan Agner 485e0a564aeSMiquel Raynal if (chip->ecc.algo == NAND_ECC_ALGO_BCH && enable) 486d7d9f8ecSStefan Agner writel_relaxed(nand->bch_config, ctrl->regs + BCH_CONFIG); 487d7d9f8ecSStefan Agner else 488d7d9f8ecSStefan Agner writel_relaxed(0, ctrl->regs + BCH_CONFIG); 489d7d9f8ecSStefan Agner 490d7d9f8ecSStefan Agner if (enable) 491d7d9f8ecSStefan Agner writel_relaxed(nand->config_ecc, ctrl->regs + CONFIG); 492d7d9f8ecSStefan Agner else 493d7d9f8ecSStefan Agner writel_relaxed(nand->config, ctrl->regs + CONFIG); 494d7d9f8ecSStefan Agner } 495d7d9f8ecSStefan Agner 496d7d9f8ecSStefan Agner static int tegra_nand_page_xfer(struct mtd_info *mtd, struct nand_chip *chip, 497d7d9f8ecSStefan Agner void *buf, void *oob_buf, int oob_len, int page, 498d7d9f8ecSStefan Agner bool read) 499d7d9f8ecSStefan Agner { 500d7d9f8ecSStefan Agner struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); 501d7d9f8ecSStefan Agner enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; 502d7d9f8ecSStefan Agner dma_addr_t dma_addr = 0, dma_addr_oob = 0; 503d7d9f8ecSStefan Agner u32 addr1, cmd, dma_ctrl; 504d7d9f8ecSStefan Agner int ret; 505d7d9f8ecSStefan Agner 5062ace451cSBoris Brezillon tegra_nand_select_target(chip, chip->cur_cs); 5072ace451cSBoris Brezillon 508d7d9f8ecSStefan Agner if (read) { 509d7d9f8ecSStefan Agner writel_relaxed(NAND_CMD_READ0, ctrl->regs + CMD_REG1); 510d7d9f8ecSStefan Agner writel_relaxed(NAND_CMD_READSTART, ctrl->regs + CMD_REG2); 511d7d9f8ecSStefan Agner } else { 512d7d9f8ecSStefan Agner writel_relaxed(NAND_CMD_SEQIN, ctrl->regs + CMD_REG1); 513d7d9f8ecSStefan Agner writel_relaxed(NAND_CMD_PAGEPROG, ctrl->regs + CMD_REG2); 514d7d9f8ecSStefan Agner } 515d7d9f8ecSStefan Agner cmd = COMMAND_CLE | COMMAND_SEC_CMD; 516d7d9f8ecSStefan Agner 517d7d9f8ecSStefan Agner /* Lower 16-bits are column, by default 0 */ 518d7d9f8ecSStefan Agner addr1 = page << 16; 519d7d9f8ecSStefan Agner 520d7d9f8ecSStefan Agner if (!buf) 521d7d9f8ecSStefan Agner addr1 |= mtd->writesize; 522d7d9f8ecSStefan Agner writel_relaxed(addr1, ctrl->regs + ADDR_REG1); 523d7d9f8ecSStefan Agner 524d7d9f8ecSStefan Agner if (chip->options & NAND_ROW_ADDR_3) { 525d7d9f8ecSStefan Agner writel_relaxed(page >> 16, ctrl->regs + ADDR_REG2); 526d7d9f8ecSStefan Agner cmd |= COMMAND_ALE | COMMAND_ALE_SIZE(5); 527d7d9f8ecSStefan Agner } else { 528d7d9f8ecSStefan Agner cmd |= COMMAND_ALE | COMMAND_ALE_SIZE(4); 529d7d9f8ecSStefan Agner } 530d7d9f8ecSStefan Agner 531d7d9f8ecSStefan Agner if (buf) { 532d7d9f8ecSStefan Agner dma_addr = dma_map_single(ctrl->dev, buf, mtd->writesize, dir); 533d7d9f8ecSStefan Agner ret = dma_mapping_error(ctrl->dev, dma_addr); 534d7d9f8ecSStefan Agner if (ret) { 535d7d9f8ecSStefan Agner dev_err(ctrl->dev, "dma mapping error\n"); 536d7d9f8ecSStefan Agner return -EINVAL; 537d7d9f8ecSStefan Agner } 538d7d9f8ecSStefan Agner 539d7d9f8ecSStefan Agner writel_relaxed(mtd->writesize - 1, ctrl->regs + DMA_CFG_A); 540d7d9f8ecSStefan Agner writel_relaxed(dma_addr, ctrl->regs + DATA_PTR); 541d7d9f8ecSStefan Agner } 542d7d9f8ecSStefan Agner 543d7d9f8ecSStefan Agner if (oob_buf) { 544d7d9f8ecSStefan Agner dma_addr_oob = dma_map_single(ctrl->dev, oob_buf, mtd->oobsize, 545d7d9f8ecSStefan Agner dir); 546d7d9f8ecSStefan Agner ret = dma_mapping_error(ctrl->dev, dma_addr_oob); 547d7d9f8ecSStefan Agner if (ret) { 548d7d9f8ecSStefan Agner dev_err(ctrl->dev, "dma mapping error\n"); 549d7d9f8ecSStefan Agner ret = -EINVAL; 550d7d9f8ecSStefan Agner goto err_unmap_dma_page; 551d7d9f8ecSStefan Agner } 552d7d9f8ecSStefan Agner 553d7d9f8ecSStefan Agner writel_relaxed(oob_len - 1, ctrl->regs + DMA_CFG_B); 554d7d9f8ecSStefan Agner writel_relaxed(dma_addr_oob, ctrl->regs + TAG_PTR); 555d7d9f8ecSStefan Agner } 556d7d9f8ecSStefan Agner 557d7d9f8ecSStefan Agner dma_ctrl = DMA_MST_CTRL_GO | DMA_MST_CTRL_PERF_EN | 558d7d9f8ecSStefan Agner DMA_MST_CTRL_IE_DONE | DMA_MST_CTRL_IS_DONE | 559d7d9f8ecSStefan Agner DMA_MST_CTRL_BURST_16; 560d7d9f8ecSStefan Agner 561d7d9f8ecSStefan Agner if (buf) 562d7d9f8ecSStefan Agner dma_ctrl |= DMA_MST_CTRL_EN_A; 563d7d9f8ecSStefan Agner if (oob_buf) 564d7d9f8ecSStefan Agner dma_ctrl |= DMA_MST_CTRL_EN_B; 565d7d9f8ecSStefan Agner 566d7d9f8ecSStefan Agner if (read) 567d7d9f8ecSStefan Agner dma_ctrl |= DMA_MST_CTRL_IN | DMA_MST_CTRL_REUSE; 568d7d9f8ecSStefan Agner else 569d7d9f8ecSStefan Agner dma_ctrl |= DMA_MST_CTRL_OUT; 570d7d9f8ecSStefan Agner 571d7d9f8ecSStefan Agner writel_relaxed(dma_ctrl, ctrl->regs + DMA_MST_CTRL); 572d7d9f8ecSStefan Agner 573d7d9f8ecSStefan Agner cmd |= COMMAND_GO | COMMAND_RBSY_CHK | COMMAND_TRANS_SIZE(9) | 574d7d9f8ecSStefan Agner COMMAND_CE(ctrl->cur_cs); 575d7d9f8ecSStefan Agner 576d7d9f8ecSStefan Agner if (buf) 577d7d9f8ecSStefan Agner cmd |= COMMAND_A_VALID; 578d7d9f8ecSStefan Agner if (oob_buf) 579d7d9f8ecSStefan Agner cmd |= COMMAND_B_VALID; 580d7d9f8ecSStefan Agner 581d7d9f8ecSStefan Agner if (read) 582d7d9f8ecSStefan Agner cmd |= COMMAND_RX; 583d7d9f8ecSStefan Agner else 584d7d9f8ecSStefan Agner cmd |= COMMAND_TX | COMMAND_AFT_DAT; 585d7d9f8ecSStefan Agner 586d7d9f8ecSStefan Agner writel_relaxed(cmd, ctrl->regs + COMMAND); 587d7d9f8ecSStefan Agner 588d7d9f8ecSStefan Agner ret = wait_for_completion_timeout(&ctrl->command_complete, 589d7d9f8ecSStefan Agner msecs_to_jiffies(500)); 590d7d9f8ecSStefan Agner if (!ret) { 591d7d9f8ecSStefan Agner dev_err(ctrl->dev, "COMMAND timeout\n"); 592d7d9f8ecSStefan Agner tegra_nand_dump_reg(ctrl); 593d7d9f8ecSStefan Agner tegra_nand_controller_abort(ctrl); 594d7d9f8ecSStefan Agner ret = -ETIMEDOUT; 595d7d9f8ecSStefan Agner goto err_unmap_dma; 596d7d9f8ecSStefan Agner } 597d7d9f8ecSStefan Agner 598d7d9f8ecSStefan Agner ret = wait_for_completion_timeout(&ctrl->dma_complete, 599d7d9f8ecSStefan Agner msecs_to_jiffies(500)); 600d7d9f8ecSStefan Agner if (!ret) { 601d7d9f8ecSStefan Agner dev_err(ctrl->dev, "DMA timeout\n"); 602d7d9f8ecSStefan Agner tegra_nand_dump_reg(ctrl); 603d7d9f8ecSStefan Agner tegra_nand_controller_abort(ctrl); 604d7d9f8ecSStefan Agner ret = -ETIMEDOUT; 605d7d9f8ecSStefan Agner goto err_unmap_dma; 606d7d9f8ecSStefan Agner } 607d7d9f8ecSStefan Agner ret = 0; 608d7d9f8ecSStefan Agner 609d7d9f8ecSStefan Agner err_unmap_dma: 610d7d9f8ecSStefan Agner if (oob_buf) 611d7d9f8ecSStefan Agner dma_unmap_single(ctrl->dev, dma_addr_oob, mtd->oobsize, dir); 612d7d9f8ecSStefan Agner err_unmap_dma_page: 613d7d9f8ecSStefan Agner if (buf) 614d7d9f8ecSStefan Agner dma_unmap_single(ctrl->dev, dma_addr, mtd->writesize, dir); 615d7d9f8ecSStefan Agner 616d7d9f8ecSStefan Agner return ret; 617d7d9f8ecSStefan Agner } 618d7d9f8ecSStefan Agner 619b9761687SBoris Brezillon static int tegra_nand_read_page_raw(struct nand_chip *chip, u8 *buf, 620d7d9f8ecSStefan Agner int oob_required, int page) 621d7d9f8ecSStefan Agner { 622b9761687SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 623d7d9f8ecSStefan Agner void *oob_buf = oob_required ? chip->oob_poi : NULL; 624d7d9f8ecSStefan Agner 625d7d9f8ecSStefan Agner return tegra_nand_page_xfer(mtd, chip, buf, oob_buf, 626d7d9f8ecSStefan Agner mtd->oobsize, page, true); 627d7d9f8ecSStefan Agner } 628d7d9f8ecSStefan Agner 629767eb6fbSBoris Brezillon static int tegra_nand_write_page_raw(struct nand_chip *chip, const u8 *buf, 630d7d9f8ecSStefan Agner int oob_required, int page) 631d7d9f8ecSStefan Agner { 632767eb6fbSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 633d7d9f8ecSStefan Agner void *oob_buf = oob_required ? chip->oob_poi : NULL; 634d7d9f8ecSStefan Agner 635d7d9f8ecSStefan Agner return tegra_nand_page_xfer(mtd, chip, (void *)buf, oob_buf, 636d7d9f8ecSStefan Agner mtd->oobsize, page, false); 637d7d9f8ecSStefan Agner } 638d7d9f8ecSStefan Agner 639b9761687SBoris Brezillon static int tegra_nand_read_oob(struct nand_chip *chip, int page) 640d7d9f8ecSStefan Agner { 641b9761687SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 642b9761687SBoris Brezillon 643d7d9f8ecSStefan Agner return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi, 644d7d9f8ecSStefan Agner mtd->oobsize, page, true); 645d7d9f8ecSStefan Agner } 646d7d9f8ecSStefan Agner 647767eb6fbSBoris Brezillon static int tegra_nand_write_oob(struct nand_chip *chip, int page) 648d7d9f8ecSStefan Agner { 649767eb6fbSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 650767eb6fbSBoris Brezillon 651d7d9f8ecSStefan Agner return tegra_nand_page_xfer(mtd, chip, NULL, chip->oob_poi, 652d7d9f8ecSStefan Agner mtd->oobsize, page, false); 653d7d9f8ecSStefan Agner } 654d7d9f8ecSStefan Agner 655b9761687SBoris Brezillon static int tegra_nand_read_page_hwecc(struct nand_chip *chip, u8 *buf, 656d7d9f8ecSStefan Agner int oob_required, int page) 657d7d9f8ecSStefan Agner { 658b9761687SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 659d7d9f8ecSStefan Agner struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); 660d7d9f8ecSStefan Agner struct tegra_nand_chip *nand = to_tegra_chip(chip); 661d7d9f8ecSStefan Agner void *oob_buf = oob_required ? chip->oob_poi : NULL; 662d7d9f8ecSStefan Agner u32 dec_stat, max_corr_cnt; 663d7d9f8ecSStefan Agner unsigned long fail_sec_flag; 664d7d9f8ecSStefan Agner int ret; 665d7d9f8ecSStefan Agner 666d7d9f8ecSStefan Agner tegra_nand_hw_ecc(ctrl, chip, true); 667d7d9f8ecSStefan Agner ret = tegra_nand_page_xfer(mtd, chip, buf, oob_buf, 0, page, true); 668d7d9f8ecSStefan Agner tegra_nand_hw_ecc(ctrl, chip, false); 669d7d9f8ecSStefan Agner if (ret) 670d7d9f8ecSStefan Agner return ret; 671d7d9f8ecSStefan Agner 672d7d9f8ecSStefan Agner /* No correctable or un-correctable errors, page must have 0 bitflips */ 673d7d9f8ecSStefan Agner if (!ctrl->last_read_error) 674d7d9f8ecSStefan Agner return 0; 675d7d9f8ecSStefan Agner 676d7d9f8ecSStefan Agner /* 677d7d9f8ecSStefan Agner * Correctable or un-correctable errors occurred. Use DEC_STAT_BUF 678d7d9f8ecSStefan Agner * which contains information for all ECC selections. 679d7d9f8ecSStefan Agner * 680d7d9f8ecSStefan Agner * Note that since we do not use Command Queues DEC_RESULT does not 681d7d9f8ecSStefan Agner * state the number of pages we can read from the DEC_STAT_BUF. But 682d7d9f8ecSStefan Agner * since CORRFAIL_ERR did occur during page read we do have a valid 683d7d9f8ecSStefan Agner * result in DEC_STAT_BUF. 684d7d9f8ecSStefan Agner */ 685d7d9f8ecSStefan Agner ctrl->last_read_error = false; 686d7d9f8ecSStefan Agner dec_stat = readl_relaxed(ctrl->regs + DEC_STAT_BUF); 687d7d9f8ecSStefan Agner 688d7d9f8ecSStefan Agner fail_sec_flag = (dec_stat & DEC_STAT_BUF_FAIL_SEC_FLAG_MASK) >> 689d7d9f8ecSStefan Agner DEC_STAT_BUF_FAIL_SEC_FLAG_SHIFT; 690d7d9f8ecSStefan Agner 691d7d9f8ecSStefan Agner max_corr_cnt = (dec_stat & DEC_STAT_BUF_MAX_CORR_CNT_MASK) >> 692d7d9f8ecSStefan Agner DEC_STAT_BUF_MAX_CORR_CNT_SHIFT; 693d7d9f8ecSStefan Agner 694d7d9f8ecSStefan Agner if (fail_sec_flag) { 695d7d9f8ecSStefan Agner int bit, max_bitflips = 0; 696d7d9f8ecSStefan Agner 697d7d9f8ecSStefan Agner /* 698d7d9f8ecSStefan Agner * Since we do not support subpage writes, a complete page 699d7d9f8ecSStefan Agner * is either written or not. We can take a shortcut here by 700d7d9f8ecSStefan Agner * checking wheather any of the sector has been successful 701d7d9f8ecSStefan Agner * read. If at least one sectors has been read successfully, 702d7d9f8ecSStefan Agner * the page must have been a written previously. It cannot 703d7d9f8ecSStefan Agner * be an erased page. 704d7d9f8ecSStefan Agner * 705d7d9f8ecSStefan Agner * E.g. controller might return fail_sec_flag with 0x4, which 706d7d9f8ecSStefan Agner * would mean only the third sector failed to correct. The 707d7d9f8ecSStefan Agner * page must have been written and the third sector is really 708d7d9f8ecSStefan Agner * not correctable anymore. 709d7d9f8ecSStefan Agner */ 710d7d9f8ecSStefan Agner if (fail_sec_flag ^ GENMASK(chip->ecc.steps - 1, 0)) { 711d7d9f8ecSStefan Agner mtd->ecc_stats.failed += hweight8(fail_sec_flag); 712d7d9f8ecSStefan Agner return max_corr_cnt; 713d7d9f8ecSStefan Agner } 714d7d9f8ecSStefan Agner 715d7d9f8ecSStefan Agner /* 716d7d9f8ecSStefan Agner * All sectors failed to correct, but the ECC isn't smart 717d7d9f8ecSStefan Agner * enough to figure out if a page is really just erased. 718d7d9f8ecSStefan Agner * Read OOB data and check whether data/OOB is completely 719d7d9f8ecSStefan Agner * erased or if error correction just failed for all sub- 720d7d9f8ecSStefan Agner * pages. 721d7d9f8ecSStefan Agner */ 722b9761687SBoris Brezillon ret = tegra_nand_read_oob(chip, page); 723d7d9f8ecSStefan Agner if (ret < 0) 724d7d9f8ecSStefan Agner return ret; 725d7d9f8ecSStefan Agner 726d7d9f8ecSStefan Agner for_each_set_bit(bit, &fail_sec_flag, chip->ecc.steps) { 727d7d9f8ecSStefan Agner u8 *data = buf + (chip->ecc.size * bit); 728d7d9f8ecSStefan Agner u8 *oob = chip->oob_poi + nand->ecc.offset + 729d7d9f8ecSStefan Agner (chip->ecc.bytes * bit); 730d7d9f8ecSStefan Agner 731d7d9f8ecSStefan Agner ret = nand_check_erased_ecc_chunk(data, chip->ecc.size, 732d7d9f8ecSStefan Agner oob, chip->ecc.bytes, 733d7d9f8ecSStefan Agner NULL, 0, 734d7d9f8ecSStefan Agner chip->ecc.strength); 735d7d9f8ecSStefan Agner if (ret < 0) { 736d7d9f8ecSStefan Agner mtd->ecc_stats.failed++; 737d7d9f8ecSStefan Agner } else { 738d7d9f8ecSStefan Agner mtd->ecc_stats.corrected += ret; 739d7d9f8ecSStefan Agner max_bitflips = max(ret, max_bitflips); 740d7d9f8ecSStefan Agner } 741d7d9f8ecSStefan Agner } 742d7d9f8ecSStefan Agner 743d7d9f8ecSStefan Agner return max_t(unsigned int, max_corr_cnt, max_bitflips); 744d7d9f8ecSStefan Agner } else { 745d7d9f8ecSStefan Agner int corr_sec_flag; 746d7d9f8ecSStefan Agner 747d7d9f8ecSStefan Agner corr_sec_flag = (dec_stat & DEC_STAT_BUF_CORR_SEC_FLAG_MASK) >> 748d7d9f8ecSStefan Agner DEC_STAT_BUF_CORR_SEC_FLAG_SHIFT; 749d7d9f8ecSStefan Agner 750d7d9f8ecSStefan Agner /* 751d7d9f8ecSStefan Agner * The value returned in the register is the maximum of 752d7d9f8ecSStefan Agner * bitflips encountered in any of the ECC regions. As there is 753d7d9f8ecSStefan Agner * no way to get the number of bitflips in a specific regions 754d7d9f8ecSStefan Agner * we are not able to deliver correct stats but instead 755d7d9f8ecSStefan Agner * overestimate the number of corrected bitflips by assuming 756d7d9f8ecSStefan Agner * that all regions where errors have been corrected 757d7d9f8ecSStefan Agner * encountered the maximum number of bitflips. 758d7d9f8ecSStefan Agner */ 759d7d9f8ecSStefan Agner mtd->ecc_stats.corrected += max_corr_cnt * hweight8(corr_sec_flag); 760d7d9f8ecSStefan Agner 761d7d9f8ecSStefan Agner return max_corr_cnt; 762d7d9f8ecSStefan Agner } 763d7d9f8ecSStefan Agner } 764d7d9f8ecSStefan Agner 765767eb6fbSBoris Brezillon static int tegra_nand_write_page_hwecc(struct nand_chip *chip, const u8 *buf, 766d7d9f8ecSStefan Agner int oob_required, int page) 767d7d9f8ecSStefan Agner { 768767eb6fbSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 769d7d9f8ecSStefan Agner struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); 770d7d9f8ecSStefan Agner void *oob_buf = oob_required ? chip->oob_poi : NULL; 771d7d9f8ecSStefan Agner int ret; 772d7d9f8ecSStefan Agner 773d7d9f8ecSStefan Agner tegra_nand_hw_ecc(ctrl, chip, true); 774d7d9f8ecSStefan Agner ret = tegra_nand_page_xfer(mtd, chip, (void *)buf, oob_buf, 775d7d9f8ecSStefan Agner 0, page, false); 776d7d9f8ecSStefan Agner tegra_nand_hw_ecc(ctrl, chip, false); 777d7d9f8ecSStefan Agner 778d7d9f8ecSStefan Agner return ret; 779d7d9f8ecSStefan Agner } 780d7d9f8ecSStefan Agner 781d7d9f8ecSStefan Agner static void tegra_nand_setup_timing(struct tegra_nand_controller *ctrl, 782d7d9f8ecSStefan Agner const struct nand_sdr_timings *timings) 783d7d9f8ecSStefan Agner { 784d7d9f8ecSStefan Agner /* 785d7d9f8ecSStefan Agner * The period (and all other timings in this function) is in ps, 786d7d9f8ecSStefan Agner * so need to take care here to avoid integer overflows. 787d7d9f8ecSStefan Agner */ 788d7d9f8ecSStefan Agner unsigned int rate = clk_get_rate(ctrl->clk) / 1000000; 789d7d9f8ecSStefan Agner unsigned int period = DIV_ROUND_UP(1000000, rate); 790d7d9f8ecSStefan Agner u32 val, reg = 0; 791d7d9f8ecSStefan Agner 792d7d9f8ecSStefan Agner val = DIV_ROUND_UP(max3(timings->tAR_min, timings->tRR_min, 793d7d9f8ecSStefan Agner timings->tRC_min), period); 794d7d9f8ecSStefan Agner reg |= TIMING_TCR_TAR_TRR(OFFSET(val, 3)); 795d7d9f8ecSStefan Agner 796d7d9f8ecSStefan Agner val = DIV_ROUND_UP(max(max(timings->tCS_min, timings->tCH_min), 797d7d9f8ecSStefan Agner max(timings->tALS_min, timings->tALH_min)), 798d7d9f8ecSStefan Agner period); 799d7d9f8ecSStefan Agner reg |= TIMING_TCS(OFFSET(val, 2)); 800d7d9f8ecSStefan Agner 801d7d9f8ecSStefan Agner val = DIV_ROUND_UP(max(timings->tRP_min, timings->tREA_max) + 6000, 802d7d9f8ecSStefan Agner period); 803d7d9f8ecSStefan Agner reg |= TIMING_TRP(OFFSET(val, 1)) | TIMING_TRP_RESP(OFFSET(val, 1)); 804d7d9f8ecSStefan Agner 805d7d9f8ecSStefan Agner reg |= TIMING_TWB(OFFSET(DIV_ROUND_UP(timings->tWB_max, period), 1)); 806d7d9f8ecSStefan Agner reg |= TIMING_TWHR(OFFSET(DIV_ROUND_UP(timings->tWHR_min, period), 1)); 807d7d9f8ecSStefan Agner reg |= TIMING_TWH(OFFSET(DIV_ROUND_UP(timings->tWH_min, period), 1)); 808d7d9f8ecSStefan Agner reg |= TIMING_TWP(OFFSET(DIV_ROUND_UP(timings->tWP_min, period), 1)); 809d7d9f8ecSStefan Agner reg |= TIMING_TRH(OFFSET(DIV_ROUND_UP(timings->tREH_min, period), 1)); 810d7d9f8ecSStefan Agner 811d7d9f8ecSStefan Agner writel_relaxed(reg, ctrl->regs + TIMING_1); 812d7d9f8ecSStefan Agner 813d7d9f8ecSStefan Agner val = DIV_ROUND_UP(timings->tADL_min, period); 814d7d9f8ecSStefan Agner reg = TIMING_TADL(OFFSET(val, 3)); 815d7d9f8ecSStefan Agner 816d7d9f8ecSStefan Agner writel_relaxed(reg, ctrl->regs + TIMING_2); 817d7d9f8ecSStefan Agner } 818d7d9f8ecSStefan Agner 8194c46667bSMiquel Raynal static int tegra_nand_setup_interface(struct nand_chip *chip, int csline, 8204c46667bSMiquel Raynal const struct nand_interface_config *conf) 821d7d9f8ecSStefan Agner { 822d7d9f8ecSStefan Agner struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); 823d7d9f8ecSStefan Agner const struct nand_sdr_timings *timings; 824d7d9f8ecSStefan Agner 825d7d9f8ecSStefan Agner timings = nand_get_sdr_timings(conf); 826d7d9f8ecSStefan Agner if (IS_ERR(timings)) 827d7d9f8ecSStefan Agner return PTR_ERR(timings); 828d7d9f8ecSStefan Agner 829d7d9f8ecSStefan Agner if (csline == NAND_DATA_IFACE_CHECK_ONLY) 830d7d9f8ecSStefan Agner return 0; 831d7d9f8ecSStefan Agner 832d7d9f8ecSStefan Agner tegra_nand_setup_timing(ctrl, timings); 833d7d9f8ecSStefan Agner 834d7d9f8ecSStefan Agner return 0; 835d7d9f8ecSStefan Agner } 836d7d9f8ecSStefan Agner 837d7d9f8ecSStefan Agner static const int rs_strength_bootable[] = { 4 }; 838d7d9f8ecSStefan Agner static const int rs_strength[] = { 4, 6, 8 }; 839d7d9f8ecSStefan Agner static const int bch_strength_bootable[] = { 8, 16 }; 840d7d9f8ecSStefan Agner static const int bch_strength[] = { 4, 8, 14, 16 }; 841d7d9f8ecSStefan Agner 842d7d9f8ecSStefan Agner static int tegra_nand_get_strength(struct nand_chip *chip, const int *strength, 843d7d9f8ecSStefan Agner int strength_len, int bits_per_step, 844d7d9f8ecSStefan Agner int oobsize) 845d7d9f8ecSStefan Agner { 846b5156335SMiquel Raynal struct nand_device *base = mtd_to_nanddev(nand_to_mtd(chip)); 84753576c7bSMiquel Raynal const struct nand_ecc_props *requirements = 848b5156335SMiquel Raynal nanddev_get_ecc_requirements(base); 849b5156335SMiquel Raynal bool maximize = base->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH; 850d7d9f8ecSStefan Agner int i; 851d7d9f8ecSStefan Agner 852d7d9f8ecSStefan Agner /* 853d7d9f8ecSStefan Agner * Loop through available strengths. Backwards in case we try to 854d7d9f8ecSStefan Agner * maximize the BCH strength. 855d7d9f8ecSStefan Agner */ 856d7d9f8ecSStefan Agner for (i = 0; i < strength_len; i++) { 857d7d9f8ecSStefan Agner int strength_sel, bytes_per_step, bytes_per_page; 858d7d9f8ecSStefan Agner 859d7d9f8ecSStefan Agner if (maximize) { 860d7d9f8ecSStefan Agner strength_sel = strength[strength_len - i - 1]; 861d7d9f8ecSStefan Agner } else { 862d7d9f8ecSStefan Agner strength_sel = strength[i]; 863d7d9f8ecSStefan Agner 86453576c7bSMiquel Raynal if (strength_sel < requirements->strength) 865d7d9f8ecSStefan Agner continue; 866d7d9f8ecSStefan Agner } 867d7d9f8ecSStefan Agner 868d7d9f8ecSStefan Agner bytes_per_step = DIV_ROUND_UP(bits_per_step * strength_sel, 869d7d9f8ecSStefan Agner BITS_PER_BYTE); 870d7d9f8ecSStefan Agner bytes_per_page = round_up(bytes_per_step * chip->ecc.steps, 4); 871d7d9f8ecSStefan Agner 872d7d9f8ecSStefan Agner /* Check whether strength fits OOB */ 873d7d9f8ecSStefan Agner if (bytes_per_page < (oobsize - SKIP_SPARE_BYTES)) 874d7d9f8ecSStefan Agner return strength_sel; 875d7d9f8ecSStefan Agner } 876d7d9f8ecSStefan Agner 877d7d9f8ecSStefan Agner return -EINVAL; 878d7d9f8ecSStefan Agner } 879d7d9f8ecSStefan Agner 880d7d9f8ecSStefan Agner static int tegra_nand_select_strength(struct nand_chip *chip, int oobsize) 881d7d9f8ecSStefan Agner { 882d7d9f8ecSStefan Agner const int *strength; 883d7d9f8ecSStefan Agner int strength_len, bits_per_step; 884d7d9f8ecSStefan Agner 885d7d9f8ecSStefan Agner switch (chip->ecc.algo) { 886e0a564aeSMiquel Raynal case NAND_ECC_ALGO_RS: 887d7d9f8ecSStefan Agner bits_per_step = BITS_PER_STEP_RS; 888d7d9f8ecSStefan Agner if (chip->options & NAND_IS_BOOT_MEDIUM) { 889d7d9f8ecSStefan Agner strength = rs_strength_bootable; 890d7d9f8ecSStefan Agner strength_len = ARRAY_SIZE(rs_strength_bootable); 891d7d9f8ecSStefan Agner } else { 892d7d9f8ecSStefan Agner strength = rs_strength; 893d7d9f8ecSStefan Agner strength_len = ARRAY_SIZE(rs_strength); 894d7d9f8ecSStefan Agner } 895d7d9f8ecSStefan Agner break; 896e0a564aeSMiquel Raynal case NAND_ECC_ALGO_BCH: 897d7d9f8ecSStefan Agner bits_per_step = BITS_PER_STEP_BCH; 898d7d9f8ecSStefan Agner if (chip->options & NAND_IS_BOOT_MEDIUM) { 899d7d9f8ecSStefan Agner strength = bch_strength_bootable; 900d7d9f8ecSStefan Agner strength_len = ARRAY_SIZE(bch_strength_bootable); 901d7d9f8ecSStefan Agner } else { 902d7d9f8ecSStefan Agner strength = bch_strength; 903d7d9f8ecSStefan Agner strength_len = ARRAY_SIZE(bch_strength); 904d7d9f8ecSStefan Agner } 905d7d9f8ecSStefan Agner break; 906d7d9f8ecSStefan Agner default: 907d7d9f8ecSStefan Agner return -EINVAL; 908d7d9f8ecSStefan Agner } 909d7d9f8ecSStefan Agner 910d7d9f8ecSStefan Agner return tegra_nand_get_strength(chip, strength, strength_len, 911d7d9f8ecSStefan Agner bits_per_step, oobsize); 912d7d9f8ecSStefan Agner } 913d7d9f8ecSStefan Agner 914176fc2f2SMiquel Raynal static int tegra_nand_attach_chip(struct nand_chip *chip) 915176fc2f2SMiquel Raynal { 916176fc2f2SMiquel Raynal struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); 91753576c7bSMiquel Raynal const struct nand_ecc_props *requirements = 91853576c7bSMiquel Raynal nanddev_get_ecc_requirements(&chip->base); 919176fc2f2SMiquel Raynal struct tegra_nand_chip *nand = to_tegra_chip(chip); 920176fc2f2SMiquel Raynal struct mtd_info *mtd = nand_to_mtd(chip); 921176fc2f2SMiquel Raynal int bits_per_step; 922176fc2f2SMiquel Raynal int ret; 923176fc2f2SMiquel Raynal 924176fc2f2SMiquel Raynal if (chip->bbt_options & NAND_BBT_USE_FLASH) 925176fc2f2SMiquel Raynal chip->bbt_options |= NAND_BBT_NO_OOB; 926176fc2f2SMiquel Raynal 927bace41f8SMiquel Raynal chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; 928176fc2f2SMiquel Raynal chip->ecc.size = 512; 929176fc2f2SMiquel Raynal chip->ecc.steps = mtd->writesize / chip->ecc.size; 93053576c7bSMiquel Raynal if (requirements->step_size != 512) { 931176fc2f2SMiquel Raynal dev_err(ctrl->dev, "Unsupported step size %d\n", 93253576c7bSMiquel Raynal requirements->step_size); 933176fc2f2SMiquel Raynal return -EINVAL; 934176fc2f2SMiquel Raynal } 935176fc2f2SMiquel Raynal 936176fc2f2SMiquel Raynal chip->ecc.read_page = tegra_nand_read_page_hwecc; 937176fc2f2SMiquel Raynal chip->ecc.write_page = tegra_nand_write_page_hwecc; 938176fc2f2SMiquel Raynal chip->ecc.read_page_raw = tegra_nand_read_page_raw; 939176fc2f2SMiquel Raynal chip->ecc.write_page_raw = tegra_nand_write_page_raw; 940176fc2f2SMiquel Raynal chip->ecc.read_oob = tegra_nand_read_oob; 941176fc2f2SMiquel Raynal chip->ecc.write_oob = tegra_nand_write_oob; 942176fc2f2SMiquel Raynal 943176fc2f2SMiquel Raynal if (chip->options & NAND_BUSWIDTH_16) 944176fc2f2SMiquel Raynal nand->config |= CONFIG_BUS_WIDTH_16; 945176fc2f2SMiquel Raynal 946e0a564aeSMiquel Raynal if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN) { 947176fc2f2SMiquel Raynal if (mtd->writesize < 2048) 948e0a564aeSMiquel Raynal chip->ecc.algo = NAND_ECC_ALGO_RS; 949176fc2f2SMiquel Raynal else 950e0a564aeSMiquel Raynal chip->ecc.algo = NAND_ECC_ALGO_BCH; 951176fc2f2SMiquel Raynal } 952176fc2f2SMiquel Raynal 953e0a564aeSMiquel Raynal if (chip->ecc.algo == NAND_ECC_ALGO_BCH && mtd->writesize < 2048) { 954176fc2f2SMiquel Raynal dev_err(ctrl->dev, "BCH supports 2K or 4K page size only\n"); 955176fc2f2SMiquel Raynal return -EINVAL; 956176fc2f2SMiquel Raynal } 957176fc2f2SMiquel Raynal 958176fc2f2SMiquel Raynal if (!chip->ecc.strength) { 959176fc2f2SMiquel Raynal ret = tegra_nand_select_strength(chip, mtd->oobsize); 960176fc2f2SMiquel Raynal if (ret < 0) { 961176fc2f2SMiquel Raynal dev_err(ctrl->dev, 962176fc2f2SMiquel Raynal "No valid strength found, minimum %d\n", 96353576c7bSMiquel Raynal requirements->strength); 964176fc2f2SMiquel Raynal return ret; 965176fc2f2SMiquel Raynal } 966176fc2f2SMiquel Raynal 967176fc2f2SMiquel Raynal chip->ecc.strength = ret; 968176fc2f2SMiquel Raynal } 969176fc2f2SMiquel Raynal 970176fc2f2SMiquel Raynal nand->config_ecc = CONFIG_PIPE_EN | CONFIG_SKIP_SPARE | 971176fc2f2SMiquel Raynal CONFIG_SKIP_SPARE_SIZE_4; 972176fc2f2SMiquel Raynal 973176fc2f2SMiquel Raynal switch (chip->ecc.algo) { 974e0a564aeSMiquel Raynal case NAND_ECC_ALGO_RS: 975176fc2f2SMiquel Raynal bits_per_step = BITS_PER_STEP_RS * chip->ecc.strength; 976176fc2f2SMiquel Raynal mtd_set_ooblayout(mtd, &tegra_nand_oob_rs_ops); 977176fc2f2SMiquel Raynal nand->config_ecc |= CONFIG_HW_ECC | CONFIG_ECC_SEL | 978176fc2f2SMiquel Raynal CONFIG_ERR_COR; 979176fc2f2SMiquel Raynal switch (chip->ecc.strength) { 980176fc2f2SMiquel Raynal case 4: 981176fc2f2SMiquel Raynal nand->config_ecc |= CONFIG_TVAL_4; 982176fc2f2SMiquel Raynal break; 983176fc2f2SMiquel Raynal case 6: 984176fc2f2SMiquel Raynal nand->config_ecc |= CONFIG_TVAL_6; 985176fc2f2SMiquel Raynal break; 986176fc2f2SMiquel Raynal case 8: 987176fc2f2SMiquel Raynal nand->config_ecc |= CONFIG_TVAL_8; 988176fc2f2SMiquel Raynal break; 989176fc2f2SMiquel Raynal default: 990176fc2f2SMiquel Raynal dev_err(ctrl->dev, "ECC strength %d not supported\n", 991176fc2f2SMiquel Raynal chip->ecc.strength); 992176fc2f2SMiquel Raynal return -EINVAL; 993176fc2f2SMiquel Raynal } 994176fc2f2SMiquel Raynal break; 995e0a564aeSMiquel Raynal case NAND_ECC_ALGO_BCH: 996176fc2f2SMiquel Raynal bits_per_step = BITS_PER_STEP_BCH * chip->ecc.strength; 997176fc2f2SMiquel Raynal mtd_set_ooblayout(mtd, &tegra_nand_oob_bch_ops); 998176fc2f2SMiquel Raynal nand->bch_config = BCH_ENABLE; 999176fc2f2SMiquel Raynal switch (chip->ecc.strength) { 1000176fc2f2SMiquel Raynal case 4: 1001176fc2f2SMiquel Raynal nand->bch_config |= BCH_TVAL_4; 1002176fc2f2SMiquel Raynal break; 1003176fc2f2SMiquel Raynal case 8: 1004176fc2f2SMiquel Raynal nand->bch_config |= BCH_TVAL_8; 1005176fc2f2SMiquel Raynal break; 1006176fc2f2SMiquel Raynal case 14: 1007176fc2f2SMiquel Raynal nand->bch_config |= BCH_TVAL_14; 1008176fc2f2SMiquel Raynal break; 1009176fc2f2SMiquel Raynal case 16: 1010176fc2f2SMiquel Raynal nand->bch_config |= BCH_TVAL_16; 1011176fc2f2SMiquel Raynal break; 1012176fc2f2SMiquel Raynal default: 1013176fc2f2SMiquel Raynal dev_err(ctrl->dev, "ECC strength %d not supported\n", 1014176fc2f2SMiquel Raynal chip->ecc.strength); 1015176fc2f2SMiquel Raynal return -EINVAL; 1016176fc2f2SMiquel Raynal } 1017176fc2f2SMiquel Raynal break; 1018176fc2f2SMiquel Raynal default: 1019176fc2f2SMiquel Raynal dev_err(ctrl->dev, "ECC algorithm not supported\n"); 1020176fc2f2SMiquel Raynal return -EINVAL; 1021176fc2f2SMiquel Raynal } 1022176fc2f2SMiquel Raynal 1023176fc2f2SMiquel Raynal dev_info(ctrl->dev, "Using %s with strength %d per 512 byte step\n", 1024e0a564aeSMiquel Raynal chip->ecc.algo == NAND_ECC_ALGO_BCH ? "BCH" : "RS", 1025176fc2f2SMiquel Raynal chip->ecc.strength); 1026176fc2f2SMiquel Raynal 1027176fc2f2SMiquel Raynal chip->ecc.bytes = DIV_ROUND_UP(bits_per_step, BITS_PER_BYTE); 1028176fc2f2SMiquel Raynal 1029176fc2f2SMiquel Raynal switch (mtd->writesize) { 1030176fc2f2SMiquel Raynal case 256: 1031176fc2f2SMiquel Raynal nand->config |= CONFIG_PS_256; 1032176fc2f2SMiquel Raynal break; 1033176fc2f2SMiquel Raynal case 512: 1034176fc2f2SMiquel Raynal nand->config |= CONFIG_PS_512; 1035176fc2f2SMiquel Raynal break; 1036176fc2f2SMiquel Raynal case 1024: 1037176fc2f2SMiquel Raynal nand->config |= CONFIG_PS_1024; 1038176fc2f2SMiquel Raynal break; 1039176fc2f2SMiquel Raynal case 2048: 1040176fc2f2SMiquel Raynal nand->config |= CONFIG_PS_2048; 1041176fc2f2SMiquel Raynal break; 1042176fc2f2SMiquel Raynal case 4096: 1043176fc2f2SMiquel Raynal nand->config |= CONFIG_PS_4096; 1044176fc2f2SMiquel Raynal break; 1045176fc2f2SMiquel Raynal default: 1046176fc2f2SMiquel Raynal dev_err(ctrl->dev, "Unsupported writesize %d\n", 1047176fc2f2SMiquel Raynal mtd->writesize); 1048176fc2f2SMiquel Raynal return -ENODEV; 1049176fc2f2SMiquel Raynal } 1050176fc2f2SMiquel Raynal 1051176fc2f2SMiquel Raynal /* Store complete configuration for HW ECC in config_ecc */ 1052176fc2f2SMiquel Raynal nand->config_ecc |= nand->config; 1053176fc2f2SMiquel Raynal 1054176fc2f2SMiquel Raynal /* Non-HW ECC read/writes complete OOB */ 1055176fc2f2SMiquel Raynal nand->config |= CONFIG_TAG_BYTE_SIZE(mtd->oobsize - 1); 1056176fc2f2SMiquel Raynal writel_relaxed(nand->config, ctrl->regs + CONFIG); 1057176fc2f2SMiquel Raynal 1058176fc2f2SMiquel Raynal return 0; 1059176fc2f2SMiquel Raynal } 1060176fc2f2SMiquel Raynal 1061176fc2f2SMiquel Raynal static const struct nand_controller_ops tegra_nand_controller_ops = { 1062176fc2f2SMiquel Raynal .attach_chip = &tegra_nand_attach_chip, 1063f2abfeb2SBoris Brezillon .exec_op = tegra_nand_exec_op, 10644c46667bSMiquel Raynal .setup_interface = tegra_nand_setup_interface, 1065176fc2f2SMiquel Raynal }; 1066176fc2f2SMiquel Raynal 1067d7d9f8ecSStefan Agner static int tegra_nand_chips_init(struct device *dev, 1068d7d9f8ecSStefan Agner struct tegra_nand_controller *ctrl) 1069d7d9f8ecSStefan Agner { 1070d7d9f8ecSStefan Agner struct device_node *np = dev->of_node; 1071d7d9f8ecSStefan Agner struct device_node *np_nand; 1072d7d9f8ecSStefan Agner int nsels, nchips = of_get_child_count(np); 1073d7d9f8ecSStefan Agner struct tegra_nand_chip *nand; 1074d7d9f8ecSStefan Agner struct mtd_info *mtd; 1075d7d9f8ecSStefan Agner struct nand_chip *chip; 1076d7d9f8ecSStefan Agner int ret; 1077d7d9f8ecSStefan Agner u32 cs; 1078d7d9f8ecSStefan Agner 1079d7d9f8ecSStefan Agner if (nchips != 1) { 1080d7d9f8ecSStefan Agner dev_err(dev, "Currently only one NAND chip supported\n"); 1081d7d9f8ecSStefan Agner return -EINVAL; 1082d7d9f8ecSStefan Agner } 1083d7d9f8ecSStefan Agner 1084d7d9f8ecSStefan Agner np_nand = of_get_next_child(np, NULL); 1085d7d9f8ecSStefan Agner 1086d7d9f8ecSStefan Agner nsels = of_property_count_elems_of_size(np_nand, "reg", sizeof(u32)); 1087d7d9f8ecSStefan Agner if (nsels != 1) { 1088d7d9f8ecSStefan Agner dev_err(dev, "Missing/invalid reg property\n"); 1089d7d9f8ecSStefan Agner return -EINVAL; 1090d7d9f8ecSStefan Agner } 1091d7d9f8ecSStefan Agner 1092d7d9f8ecSStefan Agner /* Retrieve CS id, currently only single die NAND supported */ 1093d7d9f8ecSStefan Agner ret = of_property_read_u32(np_nand, "reg", &cs); 1094d7d9f8ecSStefan Agner if (ret) { 1095d7d9f8ecSStefan Agner dev_err(dev, "could not retrieve reg property: %d\n", ret); 1096d7d9f8ecSStefan Agner return ret; 1097d7d9f8ecSStefan Agner } 1098d7d9f8ecSStefan Agner 1099d7d9f8ecSStefan Agner nand = devm_kzalloc(dev, sizeof(*nand), GFP_KERNEL); 1100d7d9f8ecSStefan Agner if (!nand) 1101d7d9f8ecSStefan Agner return -ENOMEM; 1102d7d9f8ecSStefan Agner 1103d7d9f8ecSStefan Agner nand->cs[0] = cs; 1104d7d9f8ecSStefan Agner 1105d7d9f8ecSStefan Agner nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW); 1106d7d9f8ecSStefan Agner 1107d7d9f8ecSStefan Agner if (IS_ERR(nand->wp_gpio)) { 1108d7d9f8ecSStefan Agner ret = PTR_ERR(nand->wp_gpio); 1109d7d9f8ecSStefan Agner dev_err(dev, "Failed to request WP GPIO: %d\n", ret); 1110d7d9f8ecSStefan Agner return ret; 1111d7d9f8ecSStefan Agner } 1112d7d9f8ecSStefan Agner 1113d7d9f8ecSStefan Agner chip = &nand->chip; 1114d7d9f8ecSStefan Agner chip->controller = &ctrl->controller; 1115d7d9f8ecSStefan Agner 1116d7d9f8ecSStefan Agner mtd = nand_to_mtd(chip); 1117d7d9f8ecSStefan Agner 1118d7d9f8ecSStefan Agner mtd->dev.parent = dev; 1119d7d9f8ecSStefan Agner mtd->owner = THIS_MODULE; 1120d7d9f8ecSStefan Agner 1121d7d9f8ecSStefan Agner nand_set_flash_node(chip, np_nand); 1122d7d9f8ecSStefan Agner 1123d7d9f8ecSStefan Agner if (!mtd->name) 1124d7d9f8ecSStefan Agner mtd->name = "tegra_nand"; 1125d7d9f8ecSStefan Agner 1126ce8148d7SMiquel Raynal chip->options = NAND_NO_SUBPAGE_WRITE | NAND_USES_DMA; 1127d7d9f8ecSStefan Agner 112800ad378fSBoris Brezillon ret = nand_scan(chip, 1); 1129d7d9f8ecSStefan Agner if (ret) 1130d7d9f8ecSStefan Agner return ret; 1131d7d9f8ecSStefan Agner 1132d7d9f8ecSStefan Agner mtd_ooblayout_ecc(mtd, 0, &nand->ecc); 1133d7d9f8ecSStefan Agner 1134d7d9f8ecSStefan Agner ret = mtd_device_register(mtd, NULL, 0); 1135d7d9f8ecSStefan Agner if (ret) { 1136d7d9f8ecSStefan Agner dev_err(dev, "Failed to register mtd device: %d\n", ret); 1137d7d9f8ecSStefan Agner nand_cleanup(chip); 1138d7d9f8ecSStefan Agner return ret; 1139d7d9f8ecSStefan Agner } 1140d7d9f8ecSStefan Agner 1141d7d9f8ecSStefan Agner ctrl->chip = chip; 1142d7d9f8ecSStefan Agner 1143d7d9f8ecSStefan Agner return 0; 1144d7d9f8ecSStefan Agner } 1145d7d9f8ecSStefan Agner 1146d7d9f8ecSStefan Agner static int tegra_nand_probe(struct platform_device *pdev) 1147d7d9f8ecSStefan Agner { 1148d7d9f8ecSStefan Agner struct reset_control *rst; 1149d7d9f8ecSStefan Agner struct tegra_nand_controller *ctrl; 1150d7d9f8ecSStefan Agner int err = 0; 1151d7d9f8ecSStefan Agner 1152d7d9f8ecSStefan Agner ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); 1153d7d9f8ecSStefan Agner if (!ctrl) 1154d7d9f8ecSStefan Agner return -ENOMEM; 1155d7d9f8ecSStefan Agner 1156d7d9f8ecSStefan Agner ctrl->dev = &pdev->dev; 11576902dc2fSDmitry Osipenko platform_set_drvdata(pdev, ctrl); 11587da45139SMiquel Raynal nand_controller_init(&ctrl->controller); 1159176fc2f2SMiquel Raynal ctrl->controller.ops = &tegra_nand_controller_ops; 1160d7d9f8ecSStefan Agner 11612f597bc4SCai Huoqing ctrl->regs = devm_platform_ioremap_resource(pdev, 0); 1162d7d9f8ecSStefan Agner if (IS_ERR(ctrl->regs)) 1163d7d9f8ecSStefan Agner return PTR_ERR(ctrl->regs); 1164d7d9f8ecSStefan Agner 1165d7d9f8ecSStefan Agner rst = devm_reset_control_get(&pdev->dev, "nand"); 1166d7d9f8ecSStefan Agner if (IS_ERR(rst)) 1167d7d9f8ecSStefan Agner return PTR_ERR(rst); 1168d7d9f8ecSStefan Agner 1169d7d9f8ecSStefan Agner ctrl->clk = devm_clk_get(&pdev->dev, "nand"); 1170d7d9f8ecSStefan Agner if (IS_ERR(ctrl->clk)) 1171d7d9f8ecSStefan Agner return PTR_ERR(ctrl->clk); 1172d7d9f8ecSStefan Agner 11736902dc2fSDmitry Osipenko err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); 11746902dc2fSDmitry Osipenko if (err) 11756902dc2fSDmitry Osipenko return err; 11766902dc2fSDmitry Osipenko 11776902dc2fSDmitry Osipenko /* 11786902dc2fSDmitry Osipenko * This driver doesn't support active power management yet, 11796902dc2fSDmitry Osipenko * so we will simply keep device resumed. 11806902dc2fSDmitry Osipenko */ 11816902dc2fSDmitry Osipenko pm_runtime_enable(&pdev->dev); 11826902dc2fSDmitry Osipenko err = pm_runtime_resume_and_get(&pdev->dev); 1183d7d9f8ecSStefan Agner if (err) 1184d7d9f8ecSStefan Agner return err; 1185d7d9f8ecSStefan Agner 1186d7d9f8ecSStefan Agner err = reset_control_reset(rst); 1187d7d9f8ecSStefan Agner if (err) { 1188d7d9f8ecSStefan Agner dev_err(ctrl->dev, "Failed to reset HW: %d\n", err); 11896902dc2fSDmitry Osipenko goto err_put_pm; 1190d7d9f8ecSStefan Agner } 1191d7d9f8ecSStefan Agner 1192d7d9f8ecSStefan Agner writel_relaxed(HWSTATUS_CMD_DEFAULT, ctrl->regs + HWSTATUS_CMD); 1193d7d9f8ecSStefan Agner writel_relaxed(HWSTATUS_MASK_DEFAULT, ctrl->regs + HWSTATUS_MASK); 1194d7d9f8ecSStefan Agner writel_relaxed(INT_MASK, ctrl->regs + IER); 1195d7d9f8ecSStefan Agner 1196d7d9f8ecSStefan Agner init_completion(&ctrl->command_complete); 1197d7d9f8ecSStefan Agner init_completion(&ctrl->dma_complete); 1198d7d9f8ecSStefan Agner 1199d7d9f8ecSStefan Agner ctrl->irq = platform_get_irq(pdev, 0); 1200d7d9f8ecSStefan Agner err = devm_request_irq(&pdev->dev, ctrl->irq, tegra_nand_irq, 0, 1201d7d9f8ecSStefan Agner dev_name(&pdev->dev), ctrl); 1202d7d9f8ecSStefan Agner if (err) { 1203d7d9f8ecSStefan Agner dev_err(ctrl->dev, "Failed to get IRQ: %d\n", err); 12046902dc2fSDmitry Osipenko goto err_put_pm; 1205d7d9f8ecSStefan Agner } 1206d7d9f8ecSStefan Agner 1207d7d9f8ecSStefan Agner writel_relaxed(DMA_MST_CTRL_IS_DONE, ctrl->regs + DMA_MST_CTRL); 1208d7d9f8ecSStefan Agner 1209d7d9f8ecSStefan Agner err = tegra_nand_chips_init(ctrl->dev, ctrl); 1210d7d9f8ecSStefan Agner if (err) 12116902dc2fSDmitry Osipenko goto err_put_pm; 1212d7d9f8ecSStefan Agner 1213d7d9f8ecSStefan Agner return 0; 1214d7d9f8ecSStefan Agner 12156902dc2fSDmitry Osipenko err_put_pm: 12166902dc2fSDmitry Osipenko pm_runtime_put_sync_suspend(ctrl->dev); 12176902dc2fSDmitry Osipenko pm_runtime_force_suspend(ctrl->dev); 1218d7d9f8ecSStefan Agner return err; 1219d7d9f8ecSStefan Agner } 1220d7d9f8ecSStefan Agner 1221d7d9f8ecSStefan Agner static int tegra_nand_remove(struct platform_device *pdev) 1222d7d9f8ecSStefan Agner { 1223d7d9f8ecSStefan Agner struct tegra_nand_controller *ctrl = platform_get_drvdata(pdev); 1224d7d9f8ecSStefan Agner struct nand_chip *chip = ctrl->chip; 1225d7d9f8ecSStefan Agner struct mtd_info *mtd = nand_to_mtd(chip); 1226d7d9f8ecSStefan Agner int ret; 1227d7d9f8ecSStefan Agner 1228d7d9f8ecSStefan Agner ret = mtd_device_unregister(mtd); 1229d7d9f8ecSStefan Agner if (ret) 1230d7d9f8ecSStefan Agner return ret; 1231d7d9f8ecSStefan Agner 1232d7d9f8ecSStefan Agner nand_cleanup(chip); 1233d7d9f8ecSStefan Agner 12346902dc2fSDmitry Osipenko pm_runtime_put_sync_suspend(ctrl->dev); 12356902dc2fSDmitry Osipenko pm_runtime_force_suspend(ctrl->dev); 12366902dc2fSDmitry Osipenko 12376902dc2fSDmitry Osipenko return 0; 12386902dc2fSDmitry Osipenko } 12396902dc2fSDmitry Osipenko 12406902dc2fSDmitry Osipenko static int __maybe_unused tegra_nand_runtime_resume(struct device *dev) 12416902dc2fSDmitry Osipenko { 12426902dc2fSDmitry Osipenko struct tegra_nand_controller *ctrl = dev_get_drvdata(dev); 12436902dc2fSDmitry Osipenko int err; 12446902dc2fSDmitry Osipenko 12456902dc2fSDmitry Osipenko err = clk_prepare_enable(ctrl->clk); 12466902dc2fSDmitry Osipenko if (err) { 12476902dc2fSDmitry Osipenko dev_err(dev, "Failed to enable clock: %d\n", err); 12486902dc2fSDmitry Osipenko return err; 12496902dc2fSDmitry Osipenko } 12506902dc2fSDmitry Osipenko 12516902dc2fSDmitry Osipenko return 0; 12526902dc2fSDmitry Osipenko } 12536902dc2fSDmitry Osipenko 12546902dc2fSDmitry Osipenko static int __maybe_unused tegra_nand_runtime_suspend(struct device *dev) 12556902dc2fSDmitry Osipenko { 12566902dc2fSDmitry Osipenko struct tegra_nand_controller *ctrl = dev_get_drvdata(dev); 12576902dc2fSDmitry Osipenko 1258d7d9f8ecSStefan Agner clk_disable_unprepare(ctrl->clk); 1259d7d9f8ecSStefan Agner 1260d7d9f8ecSStefan Agner return 0; 1261d7d9f8ecSStefan Agner } 1262d7d9f8ecSStefan Agner 12636902dc2fSDmitry Osipenko static const struct dev_pm_ops tegra_nand_pm = { 12646902dc2fSDmitry Osipenko SET_RUNTIME_PM_OPS(tegra_nand_runtime_suspend, tegra_nand_runtime_resume, 12656902dc2fSDmitry Osipenko NULL) 12666902dc2fSDmitry Osipenko }; 12676902dc2fSDmitry Osipenko 1268d7d9f8ecSStefan Agner static const struct of_device_id tegra_nand_of_match[] = { 1269d7d9f8ecSStefan Agner { .compatible = "nvidia,tegra20-nand" }, 1270d7d9f8ecSStefan Agner { /* sentinel */ } 1271d7d9f8ecSStefan Agner }; 1272d7d9f8ecSStefan Agner MODULE_DEVICE_TABLE(of, tegra_nand_of_match); 1273d7d9f8ecSStefan Agner 1274d7d9f8ecSStefan Agner static struct platform_driver tegra_nand_driver = { 1275d7d9f8ecSStefan Agner .driver = { 1276d7d9f8ecSStefan Agner .name = "tegra-nand", 1277d7d9f8ecSStefan Agner .of_match_table = tegra_nand_of_match, 12786902dc2fSDmitry Osipenko .pm = &tegra_nand_pm, 1279d7d9f8ecSStefan Agner }, 1280d7d9f8ecSStefan Agner .probe = tegra_nand_probe, 1281d7d9f8ecSStefan Agner .remove = tegra_nand_remove, 1282d7d9f8ecSStefan Agner }; 1283d7d9f8ecSStefan Agner module_platform_driver(tegra_nand_driver); 1284d7d9f8ecSStefan Agner 1285d7d9f8ecSStefan Agner MODULE_DESCRIPTION("NVIDIA Tegra NAND driver"); 1286d7d9f8ecSStefan Agner MODULE_AUTHOR("Thierry Reding <thierry.reding@nvidia.com>"); 1287d7d9f8ecSStefan Agner MODULE_AUTHOR("Lucas Stach <dev@lynxeye.de>"); 1288d7d9f8ecSStefan Agner MODULE_AUTHOR("Stefan Agner <stefan@agner.ch>"); 1289d7d9f8ecSStefan Agner MODULE_LICENSE("GPL v2"); 1290