1c786bbccSFabio Estevam // SPDX-License-Identifier: GPL-2.0+ 234f6e157SSascha Hauer /* 334f6e157SSascha Hauer * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. 434f6e157SSascha Hauer * Copyright 2008 Sascha Hauer, kernel@pengutronix.de 534f6e157SSascha Hauer */ 634f6e157SSascha Hauer 734f6e157SSascha Hauer #include <linux/delay.h> 834f6e157SSascha Hauer #include <linux/slab.h> 934f6e157SSascha Hauer #include <linux/init.h> 1034f6e157SSascha Hauer #include <linux/module.h> 1134f6e157SSascha Hauer #include <linux/mtd/mtd.h> 12d4092d76SBoris Brezillon #include <linux/mtd/rawnand.h> 1334f6e157SSascha Hauer #include <linux/mtd/partitions.h> 1434f6e157SSascha Hauer #include <linux/interrupt.h> 1534f6e157SSascha Hauer #include <linux/device.h> 1634f6e157SSascha Hauer #include <linux/platform_device.h> 1734f6e157SSascha Hauer #include <linux/clk.h> 1834f6e157SSascha Hauer #include <linux/err.h> 1934f6e157SSascha Hauer #include <linux/io.h> 2063f1474cSSascha Hauer #include <linux/irq.h> 2163f1474cSSascha Hauer #include <linux/completion.h> 22d367e37eSSachin Kamat #include <linux/of.h> 236436356bSUwe Kleine-König #include <linux/of_device.h> 2482906b13SArnd Bergmann #include <linux/platform_data/mtd-mxc_nand.h> 2534f6e157SSascha Hauer 2634f6e157SSascha Hauer #define DRIVER_NAME "mxc_nand" 2734f6e157SSascha Hauer 2834f6e157SSascha Hauer /* Addresses for NFC registers */ 291bc99180SSascha Hauer #define NFC_V1_V2_BUF_SIZE (host->regs + 0x00) 301bc99180SSascha Hauer #define NFC_V1_V2_BUF_ADDR (host->regs + 0x04) 311bc99180SSascha Hauer #define NFC_V1_V2_FLASH_ADDR (host->regs + 0x06) 321bc99180SSascha Hauer #define NFC_V1_V2_FLASH_CMD (host->regs + 0x08) 331bc99180SSascha Hauer #define NFC_V1_V2_CONFIG (host->regs + 0x0a) 341bc99180SSascha Hauer #define NFC_V1_V2_ECC_STATUS_RESULT (host->regs + 0x0c) 351bc99180SSascha Hauer #define NFC_V1_V2_RSLTMAIN_AREA (host->regs + 0x0e) 363f77f244SMartin Kaiser #define NFC_V21_RSLTSPARE_AREA (host->regs + 0x10) 371bc99180SSascha Hauer #define NFC_V1_V2_WRPROT (host->regs + 0x12) 381bc99180SSascha Hauer #define NFC_V1_UNLOCKSTART_BLKADDR (host->regs + 0x14) 391bc99180SSascha Hauer #define NFC_V1_UNLOCKEND_BLKADDR (host->regs + 0x16) 40d178e3e8SBaruch Siach #define NFC_V21_UNLOCKSTART_BLKADDR0 (host->regs + 0x20) 41d178e3e8SBaruch Siach #define NFC_V21_UNLOCKSTART_BLKADDR1 (host->regs + 0x24) 42d178e3e8SBaruch Siach #define NFC_V21_UNLOCKSTART_BLKADDR2 (host->regs + 0x28) 43d178e3e8SBaruch Siach #define NFC_V21_UNLOCKSTART_BLKADDR3 (host->regs + 0x2c) 44d178e3e8SBaruch Siach #define NFC_V21_UNLOCKEND_BLKADDR0 (host->regs + 0x22) 45d178e3e8SBaruch Siach #define NFC_V21_UNLOCKEND_BLKADDR1 (host->regs + 0x26) 46d178e3e8SBaruch Siach #define NFC_V21_UNLOCKEND_BLKADDR2 (host->regs + 0x2a) 47d178e3e8SBaruch Siach #define NFC_V21_UNLOCKEND_BLKADDR3 (host->regs + 0x2e) 481bc99180SSascha Hauer #define NFC_V1_V2_NF_WRPRST (host->regs + 0x18) 491bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1 (host->regs + 0x1a) 501bc99180SSascha Hauer #define NFC_V1_V2_CONFIG2 (host->regs + 0x1c) 5134f6e157SSascha Hauer 526e85dfdcSSascha Hauer #define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0) 531bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_SP_EN (1 << 2) 541bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3) 551bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_INT_MSK (1 << 4) 561bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_BIG (1 << 5) 571bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_RST (1 << 6) 581bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_CE (1 << 7) 59b8db2f51SSascha Hauer #define NFC_V2_CONFIG1_ONE_CYCLE (1 << 8) 60b8db2f51SSascha Hauer #define NFC_V2_CONFIG1_PPB(x) (((x) & 0x3) << 9) 61b8db2f51SSascha Hauer #define NFC_V2_CONFIG1_FP_INT (1 << 11) 6234f6e157SSascha Hauer 631bc99180SSascha Hauer #define NFC_V1_V2_CONFIG2_INT (1 << 15) 6434f6e157SSascha Hauer 651bc99180SSascha Hauer /* 661bc99180SSascha Hauer * Operation modes for the NFC. Valid for v1, v2 and v3 671bc99180SSascha Hauer * type controllers. 681bc99180SSascha Hauer */ 691bc99180SSascha Hauer #define NFC_CMD (1 << 0) 701bc99180SSascha Hauer #define NFC_ADDR (1 << 1) 711bc99180SSascha Hauer #define NFC_INPUT (1 << 2) 721bc99180SSascha Hauer #define NFC_OUTPUT (1 << 3) 731bc99180SSascha Hauer #define NFC_ID (1 << 4) 741bc99180SSascha Hauer #define NFC_STATUS (1 << 5) 7534f6e157SSascha Hauer 7671ec5155SSascha Hauer #define NFC_V3_FLASH_CMD (host->regs_axi + 0x00) 7771ec5155SSascha Hauer #define NFC_V3_FLASH_ADDR0 (host->regs_axi + 0x04) 7834f6e157SSascha Hauer 7971ec5155SSascha Hauer #define NFC_V3_CONFIG1 (host->regs_axi + 0x34) 8071ec5155SSascha Hauer #define NFC_V3_CONFIG1_SP_EN (1 << 0) 8171ec5155SSascha Hauer #define NFC_V3_CONFIG1_RBA(x) (((x) & 0x7 ) << 4) 8234f6e157SSascha Hauer 8371ec5155SSascha Hauer #define NFC_V3_ECC_STATUS_RESULT (host->regs_axi + 0x38) 8434f6e157SSascha Hauer 8571ec5155SSascha Hauer #define NFC_V3_LAUNCH (host->regs_axi + 0x40) 8634f6e157SSascha Hauer 8771ec5155SSascha Hauer #define NFC_V3_WRPROT (host->regs_ip + 0x0) 8871ec5155SSascha Hauer #define NFC_V3_WRPROT_LOCK_TIGHT (1 << 0) 8971ec5155SSascha Hauer #define NFC_V3_WRPROT_LOCK (1 << 1) 9071ec5155SSascha Hauer #define NFC_V3_WRPROT_UNLOCK (1 << 2) 9171ec5155SSascha Hauer #define NFC_V3_WRPROT_BLS_UNLOCK (2 << 6) 9271ec5155SSascha Hauer 9371ec5155SSascha Hauer #define NFC_V3_WRPROT_UNLOCK_BLK_ADD0 (host->regs_ip + 0x04) 9471ec5155SSascha Hauer 9571ec5155SSascha Hauer #define NFC_V3_CONFIG2 (host->regs_ip + 0x24) 9671ec5155SSascha Hauer #define NFC_V3_CONFIG2_PS_512 (0 << 0) 9771ec5155SSascha Hauer #define NFC_V3_CONFIG2_PS_2048 (1 << 0) 9871ec5155SSascha Hauer #define NFC_V3_CONFIG2_PS_4096 (2 << 0) 9971ec5155SSascha Hauer #define NFC_V3_CONFIG2_ONE_CYCLE (1 << 2) 10071ec5155SSascha Hauer #define NFC_V3_CONFIG2_ECC_EN (1 << 3) 10171ec5155SSascha Hauer #define NFC_V3_CONFIG2_2CMD_PHASES (1 << 4) 10271ec5155SSascha Hauer #define NFC_V3_CONFIG2_NUM_ADDR_PHASE0 (1 << 5) 10371ec5155SSascha Hauer #define NFC_V3_CONFIG2_ECC_MODE_8 (1 << 6) 10471718a8eSSascha Hauer #define NFC_V3_CONFIG2_PPB(x, shift) (((x) & 0x3) << shift) 10571ec5155SSascha Hauer #define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x) (((x) & 0x3) << 12) 10671ec5155SSascha Hauer #define NFC_V3_CONFIG2_INT_MSK (1 << 15) 10771ec5155SSascha Hauer #define NFC_V3_CONFIG2_ST_CMD(x) (((x) & 0xff) << 24) 10871ec5155SSascha Hauer #define NFC_V3_CONFIG2_SPAS(x) (((x) & 0xff) << 16) 10971ec5155SSascha Hauer 11071ec5155SSascha Hauer #define NFC_V3_CONFIG3 (host->regs_ip + 0x28) 11171ec5155SSascha Hauer #define NFC_V3_CONFIG3_ADD_OP(x) (((x) & 0x3) << 0) 11271ec5155SSascha Hauer #define NFC_V3_CONFIG3_FW8 (1 << 3) 11371ec5155SSascha Hauer #define NFC_V3_CONFIG3_SBB(x) (((x) & 0x7) << 8) 11471ec5155SSascha Hauer #define NFC_V3_CONFIG3_NUM_OF_DEVICES(x) (((x) & 0x7) << 12) 11571ec5155SSascha Hauer #define NFC_V3_CONFIG3_RBB_MODE (1 << 15) 11671ec5155SSascha Hauer #define NFC_V3_CONFIG3_NO_SDMA (1 << 20) 11771ec5155SSascha Hauer 11871ec5155SSascha Hauer #define NFC_V3_IPC (host->regs_ip + 0x2C) 11971ec5155SSascha Hauer #define NFC_V3_IPC_CREQ (1 << 0) 12071ec5155SSascha Hauer #define NFC_V3_IPC_INT (1 << 31) 12171ec5155SSascha Hauer 12271ec5155SSascha Hauer #define NFC_V3_DELAY_LINE (host->regs_ip + 0x34) 12334f6e157SSascha Hauer 124e4303b25SUwe Kleine-König struct mxc_nand_host; 125e4303b25SUwe Kleine-König 126e4303b25SUwe Kleine-König struct mxc_nand_devtype_data { 127e4303b25SUwe Kleine-König void (*preset)(struct mtd_info *); 12867b87f66SSascha Hauer int (*read_page)(struct nand_chip *chip, void *buf, void *oob, bool ecc, 12967b87f66SSascha Hauer int page); 130e4303b25SUwe Kleine-König void (*send_cmd)(struct mxc_nand_host *, uint16_t, int); 131e4303b25SUwe Kleine-König void (*send_addr)(struct mxc_nand_host *, uint16_t, int); 132e4303b25SUwe Kleine-König void (*send_page)(struct mtd_info *, unsigned int); 133e4303b25SUwe Kleine-König void (*send_read_id)(struct mxc_nand_host *); 134e4303b25SUwe Kleine-König uint16_t (*get_dev_status)(struct mxc_nand_host *); 135e4303b25SUwe Kleine-König int (*check_int)(struct mxc_nand_host *); 136e4303b25SUwe Kleine-König void (*irq_control)(struct mxc_nand_host *, int); 1376d38af25SUwe Kleine-König u32 (*get_ecc_status)(struct mxc_nand_host *); 138a894cf6cSBoris Brezillon const struct mtd_ooblayout_ops *ooblayout; 139758b56f5SBoris Brezillon void (*select_chip)(struct nand_chip *chip, int cs); 140858838b8SBoris Brezillon int (*setup_data_interface)(struct nand_chip *chip, int csline, 141104e442aSBoris Brezillon const struct nand_data_interface *conf); 142040bd3f6SSascha Hauer void (*enable_hwecc)(struct nand_chip *chip, bool enable); 143f48d0f9aSUwe Kleine-König 144f48d0f9aSUwe Kleine-König /* 145f48d0f9aSUwe Kleine-König * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked 146f48d0f9aSUwe Kleine-König * (CONFIG1:INT_MSK is set). To handle this the driver uses 147f48d0f9aSUwe Kleine-König * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK 148f48d0f9aSUwe Kleine-König */ 149f48d0f9aSUwe Kleine-König int irqpending_quirk; 150f48d0f9aSUwe Kleine-König int needs_ip; 151f48d0f9aSUwe Kleine-König 152f48d0f9aSUwe Kleine-König size_t regs_offset; 153f48d0f9aSUwe Kleine-König size_t spare0_offset; 154f48d0f9aSUwe Kleine-König size_t axi_offset; 155f48d0f9aSUwe Kleine-König 156f48d0f9aSUwe Kleine-König int spare_len; 157f48d0f9aSUwe Kleine-König int eccbytes; 158f48d0f9aSUwe Kleine-König int eccsize; 15971718a8eSSascha Hauer int ppb_shift; 160e4303b25SUwe Kleine-König }; 161e4303b25SUwe Kleine-König 16234f6e157SSascha Hauer struct mxc_nand_host { 16334f6e157SSascha Hauer struct nand_chip nand; 16434f6e157SSascha Hauer struct device *dev; 16534f6e157SSascha Hauer 1664b6f05e1SUwe Kleine-König void __iomem *spare0; 1674b6f05e1SUwe Kleine-König void __iomem *main_area0; 168c6de7e1bSSascha Hauer 169c6de7e1bSSascha Hauer void __iomem *base; 17034f6e157SSascha Hauer void __iomem *regs; 17171ec5155SSascha Hauer void __iomem *regs_axi; 17271ec5155SSascha Hauer void __iomem *regs_ip; 17334f6e157SSascha Hauer int status_request; 17434f6e157SSascha Hauer struct clk *clk; 17534f6e157SSascha Hauer int clk_act; 17634f6e157SSascha Hauer int irq; 17794f77e50SSascha Hauer int eccsize; 1787e7e4730SBaruch Siach int used_oobsize; 179d178e3e8SBaruch Siach int active_cs; 18034f6e157SSascha Hauer 18163f1474cSSascha Hauer struct completion op_completion; 182f8f9608dSSascha Hauer 183f8f9608dSSascha Hauer uint8_t *data_buf; 184f8f9608dSSascha Hauer unsigned int buf_start; 1855f97304eSSascha Hauer 186e4303b25SUwe Kleine-König const struct mxc_nand_devtype_data *devtype_data; 1876436356bSUwe Kleine-König struct mxc_nand_platform_data pdata; 18834f6e157SSascha Hauer }; 18934f6e157SSascha Hauer 190b2ac0376SJingoo Han static const char * const part_probes[] = { 191740bb0c4SLothar Waßmann "cmdlinepart", "RedBoot", "ofpart", NULL }; 19234f6e157SSascha Hauer 193096bcc23SSascha Hauer static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size) 194096bcc23SSascha Hauer { 195096bcc23SSascha Hauer int i; 196096bcc23SSascha Hauer u32 *t = trg; 197096bcc23SSascha Hauer const __iomem u32 *s = src; 198096bcc23SSascha Hauer 199096bcc23SSascha Hauer for (i = 0; i < (size >> 2); i++) 200096bcc23SSascha Hauer *t++ = __raw_readl(s++); 201096bcc23SSascha Hauer } 202096bcc23SSascha Hauer 2030d17fc3eSBaruch Siach static void memcpy16_fromio(void *trg, const void __iomem *src, size_t size) 2040d17fc3eSBaruch Siach { 2050d17fc3eSBaruch Siach int i; 2060d17fc3eSBaruch Siach u16 *t = trg; 2070d17fc3eSBaruch Siach const __iomem u16 *s = src; 2080d17fc3eSBaruch Siach 2090d17fc3eSBaruch Siach /* We assume that src (IO) is always 32bit aligned */ 2100d17fc3eSBaruch Siach if (PTR_ALIGN(trg, 4) == trg && IS_ALIGNED(size, 4)) { 2110d17fc3eSBaruch Siach memcpy32_fromio(trg, src, size); 2120d17fc3eSBaruch Siach return; 2130d17fc3eSBaruch Siach } 2140d17fc3eSBaruch Siach 2150d17fc3eSBaruch Siach for (i = 0; i < (size >> 1); i++) 2160d17fc3eSBaruch Siach *t++ = __raw_readw(s++); 2170d17fc3eSBaruch Siach } 2180d17fc3eSBaruch Siach 21933a87a15SKoul, Vinod static inline void memcpy32_toio(void __iomem *trg, const void *src, int size) 220096bcc23SSascha Hauer { 22133a87a15SKoul, Vinod /* __iowrite32_copy use 32bit size values so divide by 4 */ 22233a87a15SKoul, Vinod __iowrite32_copy(trg, src, size / 4); 223096bcc23SSascha Hauer } 224096bcc23SSascha Hauer 2250d17fc3eSBaruch Siach static void memcpy16_toio(void __iomem *trg, const void *src, int size) 2260d17fc3eSBaruch Siach { 2270d17fc3eSBaruch Siach int i; 2280d17fc3eSBaruch Siach __iomem u16 *t = trg; 2290d17fc3eSBaruch Siach const u16 *s = src; 2300d17fc3eSBaruch Siach 2310d17fc3eSBaruch Siach /* We assume that trg (IO) is always 32bit aligned */ 2320d17fc3eSBaruch Siach if (PTR_ALIGN(src, 4) == src && IS_ALIGNED(size, 4)) { 2330d17fc3eSBaruch Siach memcpy32_toio(trg, src, size); 2340d17fc3eSBaruch Siach return; 2350d17fc3eSBaruch Siach } 2360d17fc3eSBaruch Siach 2370d17fc3eSBaruch Siach for (i = 0; i < (size >> 1); i++) 2380d17fc3eSBaruch Siach __raw_writew(*s++, t++); 2390d17fc3eSBaruch Siach } 2400d17fc3eSBaruch Siach 24115493331SSascha Hauer /* 24215493331SSascha Hauer * The controller splits a page into data chunks of 512 bytes + partial oob. 24315493331SSascha Hauer * There are writesize / 512 such chunks, the size of the partial oob parts is 24415493331SSascha Hauer * oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then 24515493331SSascha Hauer * contains additionally the byte lost by rounding (if any). 24615493331SSascha Hauer * This function handles the needed shuffling between host->data_buf (which 24715493331SSascha Hauer * holds a page in natural order, i.e. writesize bytes data + oobsize bytes 24815493331SSascha Hauer * spare) and the NFC buffer. 24915493331SSascha Hauer */ 2501af0b314SSascha Hauer static void copy_spare(struct mtd_info *mtd, bool bfrom, void *buf) 25115493331SSascha Hauer { 25215493331SSascha Hauer struct nand_chip *this = mtd_to_nand(mtd); 25315493331SSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(this); 25415493331SSascha Hauer u16 i, oob_chunk_size; 25515493331SSascha Hauer u16 num_chunks = mtd->writesize / 512; 25615493331SSascha Hauer 2571af0b314SSascha Hauer u8 *d = buf; 25815493331SSascha Hauer u8 __iomem *s = host->spare0; 25915493331SSascha Hauer u16 sparebuf_size = host->devtype_data->spare_len; 26015493331SSascha Hauer 26115493331SSascha Hauer /* size of oob chunk for all but possibly the last one */ 26215493331SSascha Hauer oob_chunk_size = (host->used_oobsize / num_chunks) & ~1; 26315493331SSascha Hauer 26415493331SSascha Hauer if (bfrom) { 26515493331SSascha Hauer for (i = 0; i < num_chunks - 1; i++) 26615493331SSascha Hauer memcpy16_fromio(d + i * oob_chunk_size, 26715493331SSascha Hauer s + i * sparebuf_size, 26815493331SSascha Hauer oob_chunk_size); 26915493331SSascha Hauer 27015493331SSascha Hauer /* the last chunk */ 27115493331SSascha Hauer memcpy16_fromio(d + i * oob_chunk_size, 27215493331SSascha Hauer s + i * sparebuf_size, 27315493331SSascha Hauer host->used_oobsize - i * oob_chunk_size); 27415493331SSascha Hauer } else { 27515493331SSascha Hauer for (i = 0; i < num_chunks - 1; i++) 27615493331SSascha Hauer memcpy16_toio(&s[i * sparebuf_size], 27715493331SSascha Hauer &d[i * oob_chunk_size], 27815493331SSascha Hauer oob_chunk_size); 27915493331SSascha Hauer 28015493331SSascha Hauer /* the last chunk */ 28115493331SSascha Hauer memcpy16_toio(&s[i * sparebuf_size], 28215493331SSascha Hauer &d[i * oob_chunk_size], 28315493331SSascha Hauer host->used_oobsize - i * oob_chunk_size); 28415493331SSascha Hauer } 28515493331SSascha Hauer } 28615493331SSascha Hauer 28715493331SSascha Hauer /* 28815493331SSascha Hauer * MXC NANDFC can only perform full page+spare or spare-only read/write. When 28915493331SSascha Hauer * the upper layers perform a read/write buf operation, the saved column address 29015493331SSascha Hauer * is used to index into the full page. So usually this function is called with 29115493331SSascha Hauer * column == 0 (unless no column cycle is needed indicated by column == -1) 29215493331SSascha Hauer */ 29315493331SSascha Hauer static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) 29415493331SSascha Hauer { 29515493331SSascha Hauer struct nand_chip *nand_chip = mtd_to_nand(mtd); 29615493331SSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 29715493331SSascha Hauer 29815493331SSascha Hauer /* Write out column address, if necessary */ 29915493331SSascha Hauer if (column != -1) { 30015493331SSascha Hauer host->devtype_data->send_addr(host, column & 0xff, 30115493331SSascha Hauer page_addr == -1); 30215493331SSascha Hauer if (mtd->writesize > 512) 30315493331SSascha Hauer /* another col addr cycle for 2k page */ 30415493331SSascha Hauer host->devtype_data->send_addr(host, 30515493331SSascha Hauer (column >> 8) & 0xff, 30615493331SSascha Hauer false); 30715493331SSascha Hauer } 30815493331SSascha Hauer 30915493331SSascha Hauer /* Write out page address, if necessary */ 31015493331SSascha Hauer if (page_addr != -1) { 31115493331SSascha Hauer /* paddr_0 - p_addr_7 */ 31215493331SSascha Hauer host->devtype_data->send_addr(host, (page_addr & 0xff), false); 31315493331SSascha Hauer 31415493331SSascha Hauer if (mtd->writesize > 512) { 31515493331SSascha Hauer if (mtd->size >= 0x10000000) { 31615493331SSascha Hauer /* paddr_8 - paddr_15 */ 31715493331SSascha Hauer host->devtype_data->send_addr(host, 31815493331SSascha Hauer (page_addr >> 8) & 0xff, 31915493331SSascha Hauer false); 32015493331SSascha Hauer host->devtype_data->send_addr(host, 32115493331SSascha Hauer (page_addr >> 16) & 0xff, 32215493331SSascha Hauer true); 32315493331SSascha Hauer } else 32415493331SSascha Hauer /* paddr_8 - paddr_15 */ 32515493331SSascha Hauer host->devtype_data->send_addr(host, 32615493331SSascha Hauer (page_addr >> 8) & 0xff, true); 32715493331SSascha Hauer } else { 32815493331SSascha Hauer if (nand_chip->options & NAND_ROW_ADDR_3) { 32915493331SSascha Hauer /* paddr_8 - paddr_15 */ 33015493331SSascha Hauer host->devtype_data->send_addr(host, 33115493331SSascha Hauer (page_addr >> 8) & 0xff, 33215493331SSascha Hauer false); 33315493331SSascha Hauer host->devtype_data->send_addr(host, 33415493331SSascha Hauer (page_addr >> 16) & 0xff, 33515493331SSascha Hauer true); 33615493331SSascha Hauer } else 33715493331SSascha Hauer /* paddr_8 - paddr_15 */ 33815493331SSascha Hauer host->devtype_data->send_addr(host, 33915493331SSascha Hauer (page_addr >> 8) & 0xff, true); 34015493331SSascha Hauer } 34115493331SSascha Hauer } 34215493331SSascha Hauer } 34315493331SSascha Hauer 34471ec5155SSascha Hauer static int check_int_v3(struct mxc_nand_host *host) 34571ec5155SSascha Hauer { 34671ec5155SSascha Hauer uint32_t tmp; 34771ec5155SSascha Hauer 34871ec5155SSascha Hauer tmp = readl(NFC_V3_IPC); 34971ec5155SSascha Hauer if (!(tmp & NFC_V3_IPC_INT)) 35071ec5155SSascha Hauer return 0; 35171ec5155SSascha Hauer 35271ec5155SSascha Hauer tmp &= ~NFC_V3_IPC_INT; 35371ec5155SSascha Hauer writel(tmp, NFC_V3_IPC); 35471ec5155SSascha Hauer 35571ec5155SSascha Hauer return 1; 35671ec5155SSascha Hauer } 35771ec5155SSascha Hauer 3587aaf28acSSascha Hauer static int check_int_v1_v2(struct mxc_nand_host *host) 3597aaf28acSSascha Hauer { 3607aaf28acSSascha Hauer uint32_t tmp; 3617aaf28acSSascha Hauer 3621bc99180SSascha Hauer tmp = readw(NFC_V1_V2_CONFIG2); 3631bc99180SSascha Hauer if (!(tmp & NFC_V1_V2_CONFIG2_INT)) 3647aaf28acSSascha Hauer return 0; 3657aaf28acSSascha Hauer 366f48d0f9aSUwe Kleine-König if (!host->devtype_data->irqpending_quirk) 3671bc99180SSascha Hauer writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2); 3687aaf28acSSascha Hauer 3697aaf28acSSascha Hauer return 1; 3707aaf28acSSascha Hauer } 3717aaf28acSSascha Hauer 37263f1474cSSascha Hauer static void irq_control_v1_v2(struct mxc_nand_host *host, int activate) 37363f1474cSSascha Hauer { 37463f1474cSSascha Hauer uint16_t tmp; 37563f1474cSSascha Hauer 37663f1474cSSascha Hauer tmp = readw(NFC_V1_V2_CONFIG1); 37763f1474cSSascha Hauer 37863f1474cSSascha Hauer if (activate) 37963f1474cSSascha Hauer tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK; 38063f1474cSSascha Hauer else 38163f1474cSSascha Hauer tmp |= NFC_V1_V2_CONFIG1_INT_MSK; 38263f1474cSSascha Hauer 38363f1474cSSascha Hauer writew(tmp, NFC_V1_V2_CONFIG1); 38463f1474cSSascha Hauer } 38563f1474cSSascha Hauer 38663f1474cSSascha Hauer static void irq_control_v3(struct mxc_nand_host *host, int activate) 38763f1474cSSascha Hauer { 38863f1474cSSascha Hauer uint32_t tmp; 38963f1474cSSascha Hauer 39063f1474cSSascha Hauer tmp = readl(NFC_V3_CONFIG2); 39163f1474cSSascha Hauer 39263f1474cSSascha Hauer if (activate) 39363f1474cSSascha Hauer tmp &= ~NFC_V3_CONFIG2_INT_MSK; 39463f1474cSSascha Hauer else 39563f1474cSSascha Hauer tmp |= NFC_V3_CONFIG2_INT_MSK; 39663f1474cSSascha Hauer 39763f1474cSSascha Hauer writel(tmp, NFC_V3_CONFIG2); 39863f1474cSSascha Hauer } 39963f1474cSSascha Hauer 4008556958aSUwe Kleine-König static void irq_control(struct mxc_nand_host *host, int activate) 4018556958aSUwe Kleine-König { 402f48d0f9aSUwe Kleine-König if (host->devtype_data->irqpending_quirk) { 4038556958aSUwe Kleine-König if (activate) 4048556958aSUwe Kleine-König enable_irq(host->irq); 4058556958aSUwe Kleine-König else 4068556958aSUwe Kleine-König disable_irq_nosync(host->irq); 4078556958aSUwe Kleine-König } else { 408e4303b25SUwe Kleine-König host->devtype_data->irq_control(host, activate); 4098556958aSUwe Kleine-König } 4108556958aSUwe Kleine-König } 4118556958aSUwe Kleine-König 4126d38af25SUwe Kleine-König static u32 get_ecc_status_v1(struct mxc_nand_host *host) 4136d38af25SUwe Kleine-König { 4146d38af25SUwe Kleine-König return readw(NFC_V1_V2_ECC_STATUS_RESULT); 4156d38af25SUwe Kleine-König } 4166d38af25SUwe Kleine-König 4176d38af25SUwe Kleine-König static u32 get_ecc_status_v2(struct mxc_nand_host *host) 4186d38af25SUwe Kleine-König { 4196d38af25SUwe Kleine-König return readl(NFC_V1_V2_ECC_STATUS_RESULT); 4206d38af25SUwe Kleine-König } 4216d38af25SUwe Kleine-König 4226d38af25SUwe Kleine-König static u32 get_ecc_status_v3(struct mxc_nand_host *host) 4236d38af25SUwe Kleine-König { 4246d38af25SUwe Kleine-König return readl(NFC_V3_ECC_STATUS_RESULT); 4256d38af25SUwe Kleine-König } 4266d38af25SUwe Kleine-König 4278556958aSUwe Kleine-König static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) 4288556958aSUwe Kleine-König { 4298556958aSUwe Kleine-König struct mxc_nand_host *host = dev_id; 4308556958aSUwe Kleine-König 431e4303b25SUwe Kleine-König if (!host->devtype_data->check_int(host)) 4328556958aSUwe Kleine-König return IRQ_NONE; 4338556958aSUwe Kleine-König 4348556958aSUwe Kleine-König irq_control(host, 0); 4358556958aSUwe Kleine-König 4368556958aSUwe Kleine-König complete(&host->op_completion); 4378556958aSUwe Kleine-König 4388556958aSUwe Kleine-König return IRQ_HANDLED; 4398556958aSUwe Kleine-König } 4408556958aSUwe Kleine-König 44134f6e157SSascha Hauer /* This function polls the NANDFC to wait for the basic operation to 44234f6e157SSascha Hauer * complete by checking the INT bit of config2 register. 44334f6e157SSascha Hauer */ 444e35d1d8aSUwe Kleine-König static int wait_op_done(struct mxc_nand_host *host, int useirq) 44534f6e157SSascha Hauer { 446e35d1d8aSUwe Kleine-König int ret = 0; 447e35d1d8aSUwe Kleine-König 448e35d1d8aSUwe Kleine-König /* 449e35d1d8aSUwe Kleine-König * If operation is already complete, don't bother to setup an irq or a 450e35d1d8aSUwe Kleine-König * loop. 451e35d1d8aSUwe Kleine-König */ 452e35d1d8aSUwe Kleine-König if (host->devtype_data->check_int(host)) 453e35d1d8aSUwe Kleine-König return 0; 45434f6e157SSascha Hauer 45534f6e157SSascha Hauer if (useirq) { 456e35d1d8aSUwe Kleine-König unsigned long timeout; 457e35d1d8aSUwe Kleine-König 45816735d02SWolfram Sang reinit_completion(&host->op_completion); 459e35d1d8aSUwe Kleine-König 4608556958aSUwe Kleine-König irq_control(host, 1); 461e35d1d8aSUwe Kleine-König 462e35d1d8aSUwe Kleine-König timeout = wait_for_completion_timeout(&host->op_completion, HZ); 463e35d1d8aSUwe Kleine-König if (!timeout && !host->devtype_data->check_int(host)) { 464e35d1d8aSUwe Kleine-König dev_dbg(host->dev, "timeout waiting for irq\n"); 465e35d1d8aSUwe Kleine-König ret = -ETIMEDOUT; 46634f6e157SSascha Hauer } 46734f6e157SSascha Hauer } else { 468e35d1d8aSUwe Kleine-König int max_retries = 8000; 469e35d1d8aSUwe Kleine-König int done; 470e35d1d8aSUwe Kleine-König 471e35d1d8aSUwe Kleine-König do { 472e35d1d8aSUwe Kleine-König udelay(1); 473e35d1d8aSUwe Kleine-König 474e35d1d8aSUwe Kleine-König done = host->devtype_data->check_int(host); 475e35d1d8aSUwe Kleine-König if (done) 47634f6e157SSascha Hauer break; 4777aaf28acSSascha Hauer 478e35d1d8aSUwe Kleine-König } while (--max_retries); 479e35d1d8aSUwe Kleine-König 480e35d1d8aSUwe Kleine-König if (!done) { 481e35d1d8aSUwe Kleine-König dev_dbg(host->dev, "timeout polling for completion\n"); 482e35d1d8aSUwe Kleine-König ret = -ETIMEDOUT; 48334f6e157SSascha Hauer } 48434f6e157SSascha Hauer } 485e35d1d8aSUwe Kleine-König 486e35d1d8aSUwe Kleine-König WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq); 487e35d1d8aSUwe Kleine-König 488e35d1d8aSUwe Kleine-König return ret; 48934f6e157SSascha Hauer } 49034f6e157SSascha Hauer 49171ec5155SSascha Hauer static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) 49271ec5155SSascha Hauer { 49371ec5155SSascha Hauer /* fill command */ 49471ec5155SSascha Hauer writel(cmd, NFC_V3_FLASH_CMD); 49571ec5155SSascha Hauer 49671ec5155SSascha Hauer /* send out command */ 49771ec5155SSascha Hauer writel(NFC_CMD, NFC_V3_LAUNCH); 49871ec5155SSascha Hauer 49971ec5155SSascha Hauer /* Wait for operation to complete */ 50071ec5155SSascha Hauer wait_op_done(host, useirq); 50171ec5155SSascha Hauer } 50271ec5155SSascha Hauer 50334f6e157SSascha Hauer /* This function issues the specified command to the NAND device and 50434f6e157SSascha Hauer * waits for completion. */ 5055f97304eSSascha Hauer static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) 50634f6e157SSascha Hauer { 5071f3df4dcSSascha Hauer dev_dbg(host->dev, "send_cmd(host, 0x%x, %d)\n", cmd, useirq); 50834f6e157SSascha Hauer 5091bc99180SSascha Hauer writew(cmd, NFC_V1_V2_FLASH_CMD); 5101bc99180SSascha Hauer writew(NFC_CMD, NFC_V1_V2_CONFIG2); 51134f6e157SSascha Hauer 512f48d0f9aSUwe Kleine-König if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) { 513a47bfd2eSIvo Clarysse int max_retries = 100; 514a47bfd2eSIvo Clarysse /* Reset completion is indicated by NFC_CONFIG2 */ 515a47bfd2eSIvo Clarysse /* being set to 0 */ 516a47bfd2eSIvo Clarysse while (max_retries-- > 0) { 5171bc99180SSascha Hauer if (readw(NFC_V1_V2_CONFIG2) == 0) { 518a47bfd2eSIvo Clarysse break; 519a47bfd2eSIvo Clarysse } 520a47bfd2eSIvo Clarysse udelay(1); 521a47bfd2eSIvo Clarysse } 522a47bfd2eSIvo Clarysse if (max_retries < 0) 5231f3df4dcSSascha Hauer dev_dbg(host->dev, "%s: RESET failed\n", __func__); 524a47bfd2eSIvo Clarysse } else { 52534f6e157SSascha Hauer /* Wait for operation to complete */ 526c110eaf4SSascha Hauer wait_op_done(host, useirq); 52734f6e157SSascha Hauer } 528a47bfd2eSIvo Clarysse } 52934f6e157SSascha Hauer 53071ec5155SSascha Hauer static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast) 53171ec5155SSascha Hauer { 53271ec5155SSascha Hauer /* fill address */ 53371ec5155SSascha Hauer writel(addr, NFC_V3_FLASH_ADDR0); 53471ec5155SSascha Hauer 53571ec5155SSascha Hauer /* send out address */ 53671ec5155SSascha Hauer writel(NFC_ADDR, NFC_V3_LAUNCH); 53771ec5155SSascha Hauer 53871ec5155SSascha Hauer wait_op_done(host, 0); 53971ec5155SSascha Hauer } 54071ec5155SSascha Hauer 54134f6e157SSascha Hauer /* This function sends an address (or partial address) to the 54234f6e157SSascha Hauer * NAND device. The address is used to select the source/destination for 54334f6e157SSascha Hauer * a NAND command. */ 5445f97304eSSascha Hauer static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast) 54534f6e157SSascha Hauer { 5461f3df4dcSSascha Hauer dev_dbg(host->dev, "send_addr(host, 0x%x %d)\n", addr, islast); 54734f6e157SSascha Hauer 5481bc99180SSascha Hauer writew(addr, NFC_V1_V2_FLASH_ADDR); 5491bc99180SSascha Hauer writew(NFC_ADDR, NFC_V1_V2_CONFIG2); 55034f6e157SSascha Hauer 55134f6e157SSascha Hauer /* Wait for operation to complete */ 552c110eaf4SSascha Hauer wait_op_done(host, islast); 55334f6e157SSascha Hauer } 55434f6e157SSascha Hauer 55571ec5155SSascha Hauer static void send_page_v3(struct mtd_info *mtd, unsigned int ops) 55671ec5155SSascha Hauer { 5574bd4ebccSBoris BREZILLON struct nand_chip *nand_chip = mtd_to_nand(mtd); 558d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 55971ec5155SSascha Hauer uint32_t tmp; 56071ec5155SSascha Hauer 56171ec5155SSascha Hauer tmp = readl(NFC_V3_CONFIG1); 56271ec5155SSascha Hauer tmp &= ~(7 << 4); 56371ec5155SSascha Hauer writel(tmp, NFC_V3_CONFIG1); 56471ec5155SSascha Hauer 56571ec5155SSascha Hauer /* transfer data from NFC ram to nand */ 56671ec5155SSascha Hauer writel(ops, NFC_V3_LAUNCH); 56771ec5155SSascha Hauer 56871ec5155SSascha Hauer wait_op_done(host, false); 56971ec5155SSascha Hauer } 57071ec5155SSascha Hauer 5716d38af25SUwe Kleine-König static void send_page_v2(struct mtd_info *mtd, unsigned int ops) 5726d38af25SUwe Kleine-König { 5734bd4ebccSBoris BREZILLON struct nand_chip *nand_chip = mtd_to_nand(mtd); 574d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 5756d38af25SUwe Kleine-König 5766d38af25SUwe Kleine-König /* NANDFC buffer 0 is used for page read/write */ 5776d38af25SUwe Kleine-König writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); 5786d38af25SUwe Kleine-König 5796d38af25SUwe Kleine-König writew(ops, NFC_V1_V2_CONFIG2); 5806d38af25SUwe Kleine-König 5816d38af25SUwe Kleine-König /* Wait for operation to complete */ 5826d38af25SUwe Kleine-König wait_op_done(host, true); 5836d38af25SUwe Kleine-König } 5846d38af25SUwe Kleine-König 5856d38af25SUwe Kleine-König static void send_page_v1(struct mtd_info *mtd, unsigned int ops) 58634f6e157SSascha Hauer { 5874bd4ebccSBoris BREZILLON struct nand_chip *nand_chip = mtd_to_nand(mtd); 588d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 589c5d23f1bSSascha Hauer int bufs, i; 590c5d23f1bSSascha Hauer 5916d38af25SUwe Kleine-König if (mtd->writesize > 512) 592c5d23f1bSSascha Hauer bufs = 4; 593c5d23f1bSSascha Hauer else 594c5d23f1bSSascha Hauer bufs = 1; 595c5d23f1bSSascha Hauer 596c5d23f1bSSascha Hauer for (i = 0; i < bufs; i++) { 59734f6e157SSascha Hauer 59834f6e157SSascha Hauer /* NANDFC buffer 0 is used for page read/write */ 599d178e3e8SBaruch Siach writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR); 60034f6e157SSascha Hauer 6011bc99180SSascha Hauer writew(ops, NFC_V1_V2_CONFIG2); 60234f6e157SSascha Hauer 60334f6e157SSascha Hauer /* Wait for operation to complete */ 604c110eaf4SSascha Hauer wait_op_done(host, true); 60534f6e157SSascha Hauer } 60634f6e157SSascha Hauer } 60734f6e157SSascha Hauer 60871ec5155SSascha Hauer static void send_read_id_v3(struct mxc_nand_host *host) 60971ec5155SSascha Hauer { 61071ec5155SSascha Hauer /* Read ID into main buffer */ 61171ec5155SSascha Hauer writel(NFC_ID, NFC_V3_LAUNCH); 61271ec5155SSascha Hauer 61371ec5155SSascha Hauer wait_op_done(host, true); 61471ec5155SSascha Hauer 615096bcc23SSascha Hauer memcpy32_fromio(host->data_buf, host->main_area0, 16); 61671ec5155SSascha Hauer } 61771ec5155SSascha Hauer 61834f6e157SSascha Hauer /* Request the NANDFC to perform a read of the NAND device ID. */ 6195f97304eSSascha Hauer static void send_read_id_v1_v2(struct mxc_nand_host *host) 62034f6e157SSascha Hauer { 62134f6e157SSascha Hauer /* NANDFC buffer 0 is used for device ID output */ 622d178e3e8SBaruch Siach writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); 62334f6e157SSascha Hauer 6241bc99180SSascha Hauer writew(NFC_ID, NFC_V1_V2_CONFIG2); 62534f6e157SSascha Hauer 62634f6e157SSascha Hauer /* Wait for operation to complete */ 627c110eaf4SSascha Hauer wait_op_done(host, true); 62834f6e157SSascha Hauer 629096bcc23SSascha Hauer memcpy32_fromio(host->data_buf, host->main_area0, 16); 63034f6e157SSascha Hauer } 63134f6e157SSascha Hauer 63271ec5155SSascha Hauer static uint16_t get_dev_status_v3(struct mxc_nand_host *host) 63334f6e157SSascha Hauer { 63471ec5155SSascha Hauer writew(NFC_STATUS, NFC_V3_LAUNCH); 635c110eaf4SSascha Hauer wait_op_done(host, true); 63634f6e157SSascha Hauer 63771ec5155SSascha Hauer return readl(NFC_V3_CONFIG1) >> 16; 63871ec5155SSascha Hauer } 63971ec5155SSascha Hauer 64034f6e157SSascha Hauer /* This function requests the NANDFC to perform a read of the 64134f6e157SSascha Hauer * NAND device status and returns the current status. */ 6425f97304eSSascha Hauer static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host) 64334f6e157SSascha Hauer { 644c29c607aSSascha Hauer void __iomem *main_buf = host->main_area0; 64534f6e157SSascha Hauer uint32_t store; 64634f6e157SSascha Hauer uint16_t ret; 64734f6e157SSascha Hauer 648d178e3e8SBaruch Siach writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); 649c29c607aSSascha Hauer 650c29c607aSSascha Hauer /* 651c29c607aSSascha Hauer * The device status is stored in main_area0. To 652c29c607aSSascha Hauer * prevent corruption of the buffer save the value 653c29c607aSSascha Hauer * and restore it afterwards. 654c29c607aSSascha Hauer */ 65534f6e157SSascha Hauer store = readl(main_buf); 65634f6e157SSascha Hauer 6571bc99180SSascha Hauer writew(NFC_STATUS, NFC_V1_V2_CONFIG2); 65834f6e157SSascha Hauer wait_op_done(host, true); 65934f6e157SSascha Hauer 66034f6e157SSascha Hauer ret = readw(main_buf); 661c29c607aSSascha Hauer 66234f6e157SSascha Hauer writel(store, main_buf); 66334f6e157SSascha Hauer 66434f6e157SSascha Hauer return ret; 66534f6e157SSascha Hauer } 66634f6e157SSascha Hauer 667040bd3f6SSascha Hauer static void mxc_nand_enable_hwecc_v1_v2(struct nand_chip *chip, bool enable) 668040bd3f6SSascha Hauer { 669040bd3f6SSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(chip); 670040bd3f6SSascha Hauer uint16_t config1; 671040bd3f6SSascha Hauer 672040bd3f6SSascha Hauer if (chip->ecc.mode != NAND_ECC_HW) 673040bd3f6SSascha Hauer return; 674040bd3f6SSascha Hauer 675040bd3f6SSascha Hauer config1 = readw(NFC_V1_V2_CONFIG1); 676040bd3f6SSascha Hauer 677040bd3f6SSascha Hauer if (enable) 678040bd3f6SSascha Hauer config1 |= NFC_V1_V2_CONFIG1_ECC_EN; 679040bd3f6SSascha Hauer else 680040bd3f6SSascha Hauer config1 &= ~NFC_V1_V2_CONFIG1_ECC_EN; 681040bd3f6SSascha Hauer 682040bd3f6SSascha Hauer writew(config1, NFC_V1_V2_CONFIG1); 683040bd3f6SSascha Hauer } 684040bd3f6SSascha Hauer 685040bd3f6SSascha Hauer static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable) 686040bd3f6SSascha Hauer { 687040bd3f6SSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(chip); 688040bd3f6SSascha Hauer uint32_t config2; 689040bd3f6SSascha Hauer 690040bd3f6SSascha Hauer if (chip->ecc.mode != NAND_ECC_HW) 691040bd3f6SSascha Hauer return; 692040bd3f6SSascha Hauer 693040bd3f6SSascha Hauer config2 = readl(NFC_V3_CONFIG2); 694040bd3f6SSascha Hauer 695040bd3f6SSascha Hauer if (enable) 696040bd3f6SSascha Hauer config2 |= NFC_V3_CONFIG2_ECC_EN; 697040bd3f6SSascha Hauer else 698040bd3f6SSascha Hauer config2 &= ~NFC_V3_CONFIG2_ECC_EN; 699040bd3f6SSascha Hauer 700040bd3f6SSascha Hauer writel(config2, NFC_V3_CONFIG2); 701040bd3f6SSascha Hauer } 702040bd3f6SSascha Hauer 70334f6e157SSascha Hauer /* This functions is used by upper layer to checks if device is ready */ 70450a487e7SBoris Brezillon static int mxc_nand_dev_ready(struct nand_chip *chip) 70534f6e157SSascha Hauer { 70634f6e157SSascha Hauer /* 70734f6e157SSascha Hauer * NFC handles R/B internally. Therefore, this function 70834f6e157SSascha Hauer * always returns status as ready. 70934f6e157SSascha Hauer */ 71034f6e157SSascha Hauer return 1; 71134f6e157SSascha Hauer } 71234f6e157SSascha Hauer 7135039fc9fSSascha Hauer static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob, 7145039fc9fSSascha Hauer bool ecc, int page) 7155039fc9fSSascha Hauer { 7165039fc9fSSascha Hauer struct mtd_info *mtd = nand_to_mtd(chip); 7175039fc9fSSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(chip); 7185039fc9fSSascha Hauer unsigned int bitflips_corrected = 0; 7195039fc9fSSascha Hauer int no_subpages; 7205039fc9fSSascha Hauer int i; 7215039fc9fSSascha Hauer 7225039fc9fSSascha Hauer host->devtype_data->enable_hwecc(chip, ecc); 7235039fc9fSSascha Hauer 7245039fc9fSSascha Hauer host->devtype_data->send_cmd(host, NAND_CMD_READ0, false); 7255039fc9fSSascha Hauer mxc_do_addr_cycle(mtd, 0, page); 7265039fc9fSSascha Hauer 7275039fc9fSSascha Hauer if (mtd->writesize > 512) 7285039fc9fSSascha Hauer host->devtype_data->send_cmd(host, NAND_CMD_READSTART, true); 7295039fc9fSSascha Hauer 7305039fc9fSSascha Hauer no_subpages = mtd->writesize >> 9; 7315039fc9fSSascha Hauer 7325039fc9fSSascha Hauer for (i = 0; i < no_subpages; i++) { 7335039fc9fSSascha Hauer uint16_t ecc_stats; 7345039fc9fSSascha Hauer 7355039fc9fSSascha Hauer /* NANDFC buffer 0 is used for page read/write */ 7365039fc9fSSascha Hauer writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR); 7375039fc9fSSascha Hauer 7385039fc9fSSascha Hauer writew(NFC_OUTPUT, NFC_V1_V2_CONFIG2); 7395039fc9fSSascha Hauer 7405039fc9fSSascha Hauer /* Wait for operation to complete */ 7415039fc9fSSascha Hauer wait_op_done(host, true); 7425039fc9fSSascha Hauer 7435039fc9fSSascha Hauer ecc_stats = get_ecc_status_v1(host); 7445039fc9fSSascha Hauer 7455039fc9fSSascha Hauer ecc_stats >>= 2; 7465039fc9fSSascha Hauer 7475039fc9fSSascha Hauer if (buf && ecc) { 7485039fc9fSSascha Hauer switch (ecc_stats & 0x3) { 7495039fc9fSSascha Hauer case 0: 7505039fc9fSSascha Hauer default: 7515039fc9fSSascha Hauer break; 7525039fc9fSSascha Hauer case 1: 7535039fc9fSSascha Hauer mtd->ecc_stats.corrected++; 7545039fc9fSSascha Hauer bitflips_corrected = 1; 7555039fc9fSSascha Hauer break; 7565039fc9fSSascha Hauer case 2: 7575039fc9fSSascha Hauer mtd->ecc_stats.failed++; 7585039fc9fSSascha Hauer break; 7595039fc9fSSascha Hauer } 7605039fc9fSSascha Hauer } 7615039fc9fSSascha Hauer } 7625039fc9fSSascha Hauer 7635039fc9fSSascha Hauer if (buf) 7645039fc9fSSascha Hauer memcpy32_fromio(buf, host->main_area0, mtd->writesize); 7655039fc9fSSascha Hauer if (oob) 7665039fc9fSSascha Hauer copy_spare(mtd, true, oob); 7675039fc9fSSascha Hauer 7685039fc9fSSascha Hauer return bitflips_corrected; 76934f6e157SSascha Hauer } 77034f6e157SSascha Hauer 77167b87f66SSascha Hauer static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf, 77267b87f66SSascha Hauer void *oob, bool ecc, int page) 77367b87f66SSascha Hauer { 77467b87f66SSascha Hauer struct mtd_info *mtd = nand_to_mtd(chip); 77567b87f66SSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(chip); 77667b87f66SSascha Hauer unsigned int max_bitflips = 0; 77794f77e50SSascha Hauer u32 ecc_stat, err; 77867b87f66SSascha Hauer int no_subpages; 77994f77e50SSascha Hauer u8 ecc_bit_mask, err_limit; 78094f77e50SSascha Hauer 78167b87f66SSascha Hauer host->devtype_data->enable_hwecc(chip, ecc); 78267b87f66SSascha Hauer 78367b87f66SSascha Hauer host->devtype_data->send_cmd(host, NAND_CMD_READ0, false); 78467b87f66SSascha Hauer mxc_do_addr_cycle(mtd, 0, page); 78567b87f66SSascha Hauer 78667b87f66SSascha Hauer if (mtd->writesize > 512) 78767b87f66SSascha Hauer host->devtype_data->send_cmd(host, 78867b87f66SSascha Hauer NAND_CMD_READSTART, true); 78967b87f66SSascha Hauer 79067b87f66SSascha Hauer host->devtype_data->send_page(mtd, NFC_OUTPUT); 79167b87f66SSascha Hauer 79267b87f66SSascha Hauer if (buf) 79367b87f66SSascha Hauer memcpy32_fromio(buf, host->main_area0, mtd->writesize); 79467b87f66SSascha Hauer if (oob) 79567b87f66SSascha Hauer copy_spare(mtd, true, oob); 79667b87f66SSascha Hauer 79794f77e50SSascha Hauer ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf; 79894f77e50SSascha Hauer err_limit = (host->eccsize == 4) ? 0x4 : 0x8; 79994f77e50SSascha Hauer 80094f77e50SSascha Hauer no_subpages = mtd->writesize >> 9; 80194f77e50SSascha Hauer 8026d38af25SUwe Kleine-König ecc_stat = host->devtype_data->get_ecc_status(host); 80394f77e50SSascha Hauer 80494f77e50SSascha Hauer do { 80594f77e50SSascha Hauer err = ecc_stat & ecc_bit_mask; 80694f77e50SSascha Hauer if (err > err_limit) { 80767b87f66SSascha Hauer mtd->ecc_stats.failed++; 80894f77e50SSascha Hauer } else { 80967b87f66SSascha Hauer mtd->ecc_stats.corrected += err; 81067b87f66SSascha Hauer max_bitflips = max_t(unsigned int, max_bitflips, err); 81194f77e50SSascha Hauer } 81267b87f66SSascha Hauer 81394f77e50SSascha Hauer ecc_stat >>= 4; 81494f77e50SSascha Hauer } while (--no_subpages); 81594f77e50SSascha Hauer 81667b87f66SSascha Hauer return max_bitflips; 81767b87f66SSascha Hauer } 81894f77e50SSascha Hauer 819b9761687SBoris Brezillon static int mxc_nand_read_page(struct nand_chip *chip, uint8_t *buf, 820b9761687SBoris Brezillon int oob_required, int page) 82167b87f66SSascha Hauer { 82267b87f66SSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(chip); 82367b87f66SSascha Hauer void *oob_buf; 82467b87f66SSascha Hauer 82567b87f66SSascha Hauer if (oob_required) 82667b87f66SSascha Hauer oob_buf = chip->oob_poi; 82767b87f66SSascha Hauer else 82867b87f66SSascha Hauer oob_buf = NULL; 82967b87f66SSascha Hauer 83067b87f66SSascha Hauer return host->devtype_data->read_page(chip, buf, oob_buf, 1, page); 83167b87f66SSascha Hauer } 83267b87f66SSascha Hauer 833b9761687SBoris Brezillon static int mxc_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf, 834b9761687SBoris Brezillon int oob_required, int page) 83567b87f66SSascha Hauer { 83667b87f66SSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(chip); 83767b87f66SSascha Hauer void *oob_buf; 83867b87f66SSascha Hauer 83967b87f66SSascha Hauer if (oob_required) 84067b87f66SSascha Hauer oob_buf = chip->oob_poi; 84167b87f66SSascha Hauer else 84267b87f66SSascha Hauer oob_buf = NULL; 84367b87f66SSascha Hauer 84467b87f66SSascha Hauer return host->devtype_data->read_page(chip, buf, oob_buf, 0, page); 84567b87f66SSascha Hauer } 84667b87f66SSascha Hauer 847b9761687SBoris Brezillon static int mxc_nand_read_oob(struct nand_chip *chip, int page) 84867b87f66SSascha Hauer { 84967b87f66SSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(chip); 85067b87f66SSascha Hauer 85167b87f66SSascha Hauer return host->devtype_data->read_page(chip, NULL, chip->oob_poi, 0, 85267b87f66SSascha Hauer page); 85394f77e50SSascha Hauer } 85494f77e50SSascha Hauer 8556811c464SSascha Hauer static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf, 8566811c464SSascha Hauer bool ecc, int page) 8576811c464SSascha Hauer { 8586811c464SSascha Hauer struct mtd_info *mtd = nand_to_mtd(chip); 8596811c464SSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(chip); 8606811c464SSascha Hauer 8616811c464SSascha Hauer host->devtype_data->enable_hwecc(chip, ecc); 8626811c464SSascha Hauer 8636811c464SSascha Hauer host->devtype_data->send_cmd(host, NAND_CMD_SEQIN, false); 8646811c464SSascha Hauer mxc_do_addr_cycle(mtd, 0, page); 8656811c464SSascha Hauer 8666811c464SSascha Hauer memcpy32_toio(host->main_area0, buf, mtd->writesize); 8676811c464SSascha Hauer copy_spare(mtd, false, chip->oob_poi); 8686811c464SSascha Hauer 8696811c464SSascha Hauer host->devtype_data->send_page(mtd, NFC_INPUT); 8706811c464SSascha Hauer host->devtype_data->send_cmd(host, NAND_CMD_PAGEPROG, true); 8716811c464SSascha Hauer mxc_do_addr_cycle(mtd, 0, page); 8726811c464SSascha Hauer 8736811c464SSascha Hauer return 0; 8746811c464SSascha Hauer } 8756811c464SSascha Hauer 876767eb6fbSBoris Brezillon static int mxc_nand_write_page_ecc(struct nand_chip *chip, const uint8_t *buf, 877767eb6fbSBoris Brezillon int oob_required, int page) 8786811c464SSascha Hauer { 8796811c464SSascha Hauer return mxc_nand_write_page(chip, buf, true, page); 8806811c464SSascha Hauer } 8816811c464SSascha Hauer 882767eb6fbSBoris Brezillon static int mxc_nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf, 883767eb6fbSBoris Brezillon int oob_required, int page) 8846811c464SSascha Hauer { 8856811c464SSascha Hauer return mxc_nand_write_page(chip, buf, false, page); 8866811c464SSascha Hauer } 8876811c464SSascha Hauer 888767eb6fbSBoris Brezillon static int mxc_nand_write_oob(struct nand_chip *chip, int page) 8896811c464SSascha Hauer { 890767eb6fbSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 8916811c464SSascha Hauer struct mxc_nand_host *host = nand_get_controller_data(chip); 8926811c464SSascha Hauer 8936811c464SSascha Hauer memset(host->data_buf, 0xff, mtd->writesize); 8946811c464SSascha Hauer 8956811c464SSascha Hauer return mxc_nand_write_page(chip, host->data_buf, false, page); 8966811c464SSascha Hauer } 8976811c464SSascha Hauer 8987e534323SBoris Brezillon static u_char mxc_nand_read_byte(struct nand_chip *nand_chip) 89934f6e157SSascha Hauer { 900d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 901f8f9608dSSascha Hauer uint8_t ret; 90234f6e157SSascha Hauer 90334f6e157SSascha Hauer /* Check for status request */ 90434f6e157SSascha Hauer if (host->status_request) 905e4303b25SUwe Kleine-König return host->devtype_data->get_dev_status(host) & 0xFF; 90634f6e157SSascha Hauer 9073f410690SUwe Kleine-König if (nand_chip->options & NAND_BUSWIDTH_16) { 9083f410690SUwe Kleine-König /* only take the lower byte of each word */ 9093f410690SUwe Kleine-König ret = *(uint16_t *)(host->data_buf + host->buf_start); 9103f410690SUwe Kleine-König 9113f410690SUwe Kleine-König host->buf_start += 2; 9123f410690SUwe Kleine-König } else { 913f8f9608dSSascha Hauer ret = *(uint8_t *)(host->data_buf + host->buf_start); 914f8f9608dSSascha Hauer host->buf_start++; 9153f410690SUwe Kleine-König } 91634f6e157SSascha Hauer 9171f3df4dcSSascha Hauer dev_dbg(host->dev, "%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start); 91834f6e157SSascha Hauer return ret; 91934f6e157SSascha Hauer } 92034f6e157SSascha Hauer 92134f6e157SSascha Hauer /* Write data of length len to buffer buf. The data to be 92234f6e157SSascha Hauer * written on NAND Flash is first copied to RAMbuffer. After the Data Input 92334f6e157SSascha Hauer * Operation by the NFC, the data is written to NAND Flash */ 924c0739d85SBoris Brezillon static void mxc_nand_write_buf(struct nand_chip *nand_chip, const u_char *buf, 925c0739d85SBoris Brezillon int len) 92634f6e157SSascha Hauer { 927c0739d85SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(nand_chip); 928d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 929f8f9608dSSascha Hauer u16 col = host->buf_start; 930f8f9608dSSascha Hauer int n = mtd->oobsize + mtd->writesize - col; 93134f6e157SSascha Hauer 932f8f9608dSSascha Hauer n = min(n, len); 93334f6e157SSascha Hauer 934f8f9608dSSascha Hauer memcpy(host->data_buf + col, buf, n); 93534f6e157SSascha Hauer 936f8f9608dSSascha Hauer host->buf_start += n; 93734f6e157SSascha Hauer } 93834f6e157SSascha Hauer 93934f6e157SSascha Hauer /* Read the data buffer from the NAND Flash. To read the data from NAND 94034f6e157SSascha Hauer * Flash first the data output cycle is initiated by the NFC, which copies 94134f6e157SSascha Hauer * the data to RAMbuffer. This data of length len is then copied to buffer buf. 94234f6e157SSascha Hauer */ 9437e534323SBoris Brezillon static void mxc_nand_read_buf(struct nand_chip *nand_chip, u_char *buf, 9447e534323SBoris Brezillon int len) 94534f6e157SSascha Hauer { 9467e534323SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(nand_chip); 947d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 948f8f9608dSSascha Hauer u16 col = host->buf_start; 949f8f9608dSSascha Hauer int n = mtd->oobsize + mtd->writesize - col; 95034f6e157SSascha Hauer 951f8f9608dSSascha Hauer n = min(n, len); 95234f6e157SSascha Hauer 9535d9d9936SBaruch Siach memcpy(buf, host->data_buf + col, n); 95434f6e157SSascha Hauer 9555d9d9936SBaruch Siach host->buf_start += n; 95634f6e157SSascha Hauer } 95734f6e157SSascha Hauer 95834f6e157SSascha Hauer /* This function is used by upper layer for select and 95934f6e157SSascha Hauer * deselect of the NAND chip */ 960758b56f5SBoris Brezillon static void mxc_nand_select_chip_v1_v3(struct nand_chip *nand_chip, int chip) 96134f6e157SSascha Hauer { 962d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 96334f6e157SSascha Hauer 964d178e3e8SBaruch Siach if (chip == -1) { 96534f6e157SSascha Hauer /* Disable the NFC clock */ 96634f6e157SSascha Hauer if (host->clk_act) { 96797c3213fSSascha Hauer clk_disable_unprepare(host->clk); 96834f6e157SSascha Hauer host->clk_act = 0; 96934f6e157SSascha Hauer } 970d178e3e8SBaruch Siach return; 971d178e3e8SBaruch Siach } 972d178e3e8SBaruch Siach 97334f6e157SSascha Hauer if (!host->clk_act) { 974d178e3e8SBaruch Siach /* Enable the NFC clock */ 97597c3213fSSascha Hauer clk_prepare_enable(host->clk); 97634f6e157SSascha Hauer host->clk_act = 1; 97734f6e157SSascha Hauer } 9785e05a2d6SUwe Kleine-König } 97934f6e157SSascha Hauer 980758b56f5SBoris Brezillon static void mxc_nand_select_chip_v2(struct nand_chip *nand_chip, int chip) 98134f6e157SSascha Hauer { 982d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 98334f6e157SSascha Hauer 98434f6e157SSascha Hauer if (chip == -1) { 98534f6e157SSascha Hauer /* Disable the NFC clock */ 98634f6e157SSascha Hauer if (host->clk_act) { 9873d059693SFabio Estevam clk_disable_unprepare(host->clk); 98834f6e157SSascha Hauer host->clk_act = 0; 98934f6e157SSascha Hauer } 99034f6e157SSascha Hauer return; 99134f6e157SSascha Hauer } 99234f6e157SSascha Hauer 99334f6e157SSascha Hauer if (!host->clk_act) { 99434f6e157SSascha Hauer /* Enable the NFC clock */ 9953d059693SFabio Estevam clk_prepare_enable(host->clk); 99634f6e157SSascha Hauer host->clk_act = 1; 99734f6e157SSascha Hauer } 99834f6e157SSascha Hauer 999d178e3e8SBaruch Siach host->active_cs = chip; 1000d178e3e8SBaruch Siach writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); 100134f6e157SSascha Hauer } 100234f6e157SSascha Hauer 10033bff08dfSBoris Brezillon #define MXC_V1_ECCBYTES 5 10043bff08dfSBoris Brezillon 1005a894cf6cSBoris Brezillon static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section, 1006a894cf6cSBoris Brezillon struct mtd_oob_region *oobregion) 1007a894cf6cSBoris Brezillon { 1008a894cf6cSBoris Brezillon struct nand_chip *nand_chip = mtd_to_nand(mtd); 1009a894cf6cSBoris Brezillon 1010a894cf6cSBoris Brezillon if (section >= nand_chip->ecc.steps) 1011a894cf6cSBoris Brezillon return -ERANGE; 1012a894cf6cSBoris Brezillon 1013a894cf6cSBoris Brezillon oobregion->offset = (section * 16) + 6; 10143bff08dfSBoris Brezillon oobregion->length = MXC_V1_ECCBYTES; 1015a894cf6cSBoris Brezillon 1016a894cf6cSBoris Brezillon return 0; 1017a894cf6cSBoris Brezillon } 1018a894cf6cSBoris Brezillon 1019a894cf6cSBoris Brezillon static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section, 1020a894cf6cSBoris Brezillon struct mtd_oob_region *oobregion) 1021a894cf6cSBoris Brezillon { 1022a894cf6cSBoris Brezillon struct nand_chip *nand_chip = mtd_to_nand(mtd); 1023a894cf6cSBoris Brezillon 1024a894cf6cSBoris Brezillon if (section > nand_chip->ecc.steps) 1025a894cf6cSBoris Brezillon return -ERANGE; 1026a894cf6cSBoris Brezillon 1027a894cf6cSBoris Brezillon if (!section) { 1028a894cf6cSBoris Brezillon if (mtd->writesize <= 512) { 1029a894cf6cSBoris Brezillon oobregion->offset = 0; 1030a894cf6cSBoris Brezillon oobregion->length = 5; 1031a894cf6cSBoris Brezillon } else { 1032a894cf6cSBoris Brezillon oobregion->offset = 2; 1033a894cf6cSBoris Brezillon oobregion->length = 4; 1034a894cf6cSBoris Brezillon } 1035a894cf6cSBoris Brezillon } else { 10363bff08dfSBoris Brezillon oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6; 1037a894cf6cSBoris Brezillon if (section < nand_chip->ecc.steps) 1038a894cf6cSBoris Brezillon oobregion->length = (section * 16) + 6 - 1039a894cf6cSBoris Brezillon oobregion->offset; 1040a894cf6cSBoris Brezillon else 1041a894cf6cSBoris Brezillon oobregion->length = mtd->oobsize - oobregion->offset; 1042a894cf6cSBoris Brezillon } 1043a894cf6cSBoris Brezillon 1044a894cf6cSBoris Brezillon return 0; 1045a894cf6cSBoris Brezillon } 1046a894cf6cSBoris Brezillon 1047a894cf6cSBoris Brezillon static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = { 1048a894cf6cSBoris Brezillon .ecc = mxc_v1_ooblayout_ecc, 1049a894cf6cSBoris Brezillon .free = mxc_v1_ooblayout_free, 1050a894cf6cSBoris Brezillon }; 1051a894cf6cSBoris Brezillon 1052a894cf6cSBoris Brezillon static int mxc_v2_ooblayout_ecc(struct mtd_info *mtd, int section, 1053a894cf6cSBoris Brezillon struct mtd_oob_region *oobregion) 1054a894cf6cSBoris Brezillon { 1055a894cf6cSBoris Brezillon struct nand_chip *nand_chip = mtd_to_nand(mtd); 1056a894cf6cSBoris Brezillon int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26; 1057a894cf6cSBoris Brezillon 1058a894cf6cSBoris Brezillon if (section >= nand_chip->ecc.steps) 1059a894cf6cSBoris Brezillon return -ERANGE; 1060a894cf6cSBoris Brezillon 1061a894cf6cSBoris Brezillon oobregion->offset = (section * stepsize) + 7; 1062a894cf6cSBoris Brezillon oobregion->length = nand_chip->ecc.bytes; 1063a894cf6cSBoris Brezillon 1064a894cf6cSBoris Brezillon return 0; 1065a894cf6cSBoris Brezillon } 1066a894cf6cSBoris Brezillon 1067a894cf6cSBoris Brezillon static int mxc_v2_ooblayout_free(struct mtd_info *mtd, int section, 1068a894cf6cSBoris Brezillon struct mtd_oob_region *oobregion) 1069a894cf6cSBoris Brezillon { 1070a894cf6cSBoris Brezillon struct nand_chip *nand_chip = mtd_to_nand(mtd); 1071a894cf6cSBoris Brezillon int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26; 1072a894cf6cSBoris Brezillon 107338178e7bSLothar Waßmann if (section >= nand_chip->ecc.steps) 1074a894cf6cSBoris Brezillon return -ERANGE; 1075a894cf6cSBoris Brezillon 1076a894cf6cSBoris Brezillon if (!section) { 1077a894cf6cSBoris Brezillon if (mtd->writesize <= 512) { 1078a894cf6cSBoris Brezillon oobregion->offset = 0; 1079a894cf6cSBoris Brezillon oobregion->length = 5; 1080a894cf6cSBoris Brezillon } else { 1081a894cf6cSBoris Brezillon oobregion->offset = 2; 1082a894cf6cSBoris Brezillon oobregion->length = 4; 1083a894cf6cSBoris Brezillon } 1084a894cf6cSBoris Brezillon } else { 1085a894cf6cSBoris Brezillon oobregion->offset = section * stepsize; 1086a894cf6cSBoris Brezillon oobregion->length = 7; 1087a894cf6cSBoris Brezillon } 1088a894cf6cSBoris Brezillon 1089a894cf6cSBoris Brezillon return 0; 1090a894cf6cSBoris Brezillon } 1091a894cf6cSBoris Brezillon 1092a894cf6cSBoris Brezillon static const struct mtd_ooblayout_ops mxc_v2_ooblayout_ops = { 1093a894cf6cSBoris Brezillon .ecc = mxc_v2_ooblayout_ecc, 1094a894cf6cSBoris Brezillon .free = mxc_v2_ooblayout_free, 1095a894cf6cSBoris Brezillon }; 1096a894cf6cSBoris Brezillon 10976e85dfdcSSascha Hauer /* 10986e85dfdcSSascha Hauer * v2 and v3 type controllers can do 4bit or 8bit ecc depending 10996e85dfdcSSascha Hauer * on how much oob the nand chip has. For 8bit ecc we need at least 11006e85dfdcSSascha Hauer * 26 bytes of oob data per 512 byte block. 11016e85dfdcSSascha Hauer */ 11026e85dfdcSSascha Hauer static int get_eccsize(struct mtd_info *mtd) 11036e85dfdcSSascha Hauer { 11046e85dfdcSSascha Hauer int oobbytes_per_512 = 0; 11056e85dfdcSSascha Hauer 11066e85dfdcSSascha Hauer oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize; 11076e85dfdcSSascha Hauer 11086e85dfdcSSascha Hauer if (oobbytes_per_512 < 26) 11096e85dfdcSSascha Hauer return 4; 11106e85dfdcSSascha Hauer else 11116e85dfdcSSascha Hauer return 8; 11126e85dfdcSSascha Hauer } 11136e85dfdcSSascha Hauer 11146d38af25SUwe Kleine-König static void preset_v1(struct mtd_info *mtd) 1115d4840180SIvo Clarysse { 11164bd4ebccSBoris BREZILLON struct nand_chip *nand_chip = mtd_to_nand(mtd); 1117d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 1118b8db2f51SSascha Hauer uint16_t config1 = 0; 1119d4840180SIvo Clarysse 11201f42adc8SUwe Kleine-König if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize) 1121b8db2f51SSascha Hauer config1 |= NFC_V1_V2_CONFIG1_ECC_EN; 1122b8db2f51SSascha Hauer 1123f48d0f9aSUwe Kleine-König if (!host->devtype_data->irqpending_quirk) 1124b8db2f51SSascha Hauer config1 |= NFC_V1_V2_CONFIG1_INT_MSK; 11256e85dfdcSSascha Hauer 11266d38af25SUwe Kleine-König host->eccsize = 1; 11276d38af25SUwe Kleine-König 11286d38af25SUwe Kleine-König writew(config1, NFC_V1_V2_CONFIG1); 11296d38af25SUwe Kleine-König /* preset operation */ 11306d38af25SUwe Kleine-König 11316d38af25SUwe Kleine-König /* Unlock the internal RAM Buffer */ 11326d38af25SUwe Kleine-König writew(0x2, NFC_V1_V2_CONFIG); 11336d38af25SUwe Kleine-König 11346d38af25SUwe Kleine-König /* Blocks to be unlocked */ 11356d38af25SUwe Kleine-König writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR); 11366d38af25SUwe Kleine-König writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR); 11376d38af25SUwe Kleine-König 11386d38af25SUwe Kleine-König /* Unlock Block Command for given address range */ 11396d38af25SUwe Kleine-König writew(0x4, NFC_V1_V2_WRPROT); 11406d38af25SUwe Kleine-König } 11416d38af25SUwe Kleine-König 1142858838b8SBoris Brezillon static int mxc_nand_v2_setup_data_interface(struct nand_chip *chip, int csline, 1143104e442aSBoris Brezillon const struct nand_data_interface *conf) 114482830796SSascha Hauer { 1145858838b8SBoris Brezillon struct mxc_nand_host *host = nand_get_controller_data(chip); 114682830796SSascha Hauer int tRC_min_ns, tRC_ps, ret; 114782830796SSascha Hauer unsigned long rate, rate_round; 114882830796SSascha Hauer const struct nand_sdr_timings *timings; 114982830796SSascha Hauer u16 config1; 115082830796SSascha Hauer 115182830796SSascha Hauer timings = nand_get_sdr_timings(conf); 115282830796SSascha Hauer if (IS_ERR(timings)) 115382830796SSascha Hauer return -ENOTSUPP; 115482830796SSascha Hauer 115582830796SSascha Hauer config1 = readw(NFC_V1_V2_CONFIG1); 115682830796SSascha Hauer 115782830796SSascha Hauer tRC_min_ns = timings->tRC_min / 1000; 115882830796SSascha Hauer rate = 1000000000 / tRC_min_ns; 115982830796SSascha Hauer 116082830796SSascha Hauer /* 116182830796SSascha Hauer * For tRC < 30ns we have to use EDO mode. In this case the controller 116282830796SSascha Hauer * does one access per clock cycle. Otherwise the controller does one 116382830796SSascha Hauer * access in two clock cycles, thus we have to double the rate to the 116482830796SSascha Hauer * controller. 116582830796SSascha Hauer */ 116682830796SSascha Hauer if (tRC_min_ns < 30) { 116782830796SSascha Hauer rate_round = clk_round_rate(host->clk, rate); 116882830796SSascha Hauer config1 |= NFC_V2_CONFIG1_ONE_CYCLE; 116982830796SSascha Hauer tRC_ps = 1000000000 / (rate_round / 1000); 117082830796SSascha Hauer } else { 117182830796SSascha Hauer rate *= 2; 117282830796SSascha Hauer rate_round = clk_round_rate(host->clk, rate); 117382830796SSascha Hauer config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE; 117482830796SSascha Hauer tRC_ps = 1000000000 / (rate_round / 1000 / 2); 117582830796SSascha Hauer } 117682830796SSascha Hauer 117782830796SSascha Hauer /* 117882830796SSascha Hauer * The timing values compared against are from the i.MX25 Automotive 117982830796SSascha Hauer * datasheet, Table 50. NFC Timing Parameters 118082830796SSascha Hauer */ 118182830796SSascha Hauer if (timings->tCLS_min > tRC_ps - 1000 || 118282830796SSascha Hauer timings->tCLH_min > tRC_ps - 2000 || 118382830796SSascha Hauer timings->tCS_min > tRC_ps - 1000 || 118482830796SSascha Hauer timings->tCH_min > tRC_ps - 2000 || 118582830796SSascha Hauer timings->tWP_min > tRC_ps - 1500 || 118682830796SSascha Hauer timings->tALS_min > tRC_ps || 118782830796SSascha Hauer timings->tALH_min > tRC_ps - 3000 || 118882830796SSascha Hauer timings->tDS_min > tRC_ps || 118982830796SSascha Hauer timings->tDH_min > tRC_ps - 5000 || 119082830796SSascha Hauer timings->tWC_min > 2 * tRC_ps || 119182830796SSascha Hauer timings->tWH_min > tRC_ps - 2500 || 119282830796SSascha Hauer timings->tRR_min > 6 * tRC_ps || 119382830796SSascha Hauer timings->tRP_min > 3 * tRC_ps / 2 || 119482830796SSascha Hauer timings->tRC_min > 2 * tRC_ps || 119582830796SSascha Hauer timings->tREH_min > (tRC_ps / 2) - 2500) { 119682830796SSascha Hauer dev_dbg(host->dev, "Timing out of bounds\n"); 119782830796SSascha Hauer return -EINVAL; 119882830796SSascha Hauer } 119982830796SSascha Hauer 1200104e442aSBoris Brezillon if (csline == NAND_DATA_IFACE_CHECK_ONLY) 120182830796SSascha Hauer return 0; 120282830796SSascha Hauer 120382830796SSascha Hauer ret = clk_set_rate(host->clk, rate); 120482830796SSascha Hauer if (ret) 120582830796SSascha Hauer return ret; 120682830796SSascha Hauer 120782830796SSascha Hauer writew(config1, NFC_V1_V2_CONFIG1); 120882830796SSascha Hauer 120982830796SSascha Hauer dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round, 121082830796SSascha Hauer config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" : 121182830796SSascha Hauer "normal"); 121282830796SSascha Hauer 121382830796SSascha Hauer return 0; 121482830796SSascha Hauer } 121582830796SSascha Hauer 12166d38af25SUwe Kleine-König static void preset_v2(struct mtd_info *mtd) 12176d38af25SUwe Kleine-König { 12184bd4ebccSBoris BREZILLON struct nand_chip *nand_chip = mtd_to_nand(mtd); 1219d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 12206d38af25SUwe Kleine-König uint16_t config1 = 0; 12216d38af25SUwe Kleine-König 1222d4840180SIvo Clarysse config1 |= NFC_V2_CONFIG1_FP_INT; 1223d4840180SIvo Clarysse 1224f48d0f9aSUwe Kleine-König if (!host->devtype_data->irqpending_quirk) 1225d4840180SIvo Clarysse config1 |= NFC_V1_V2_CONFIG1_INT_MSK; 12266e85dfdcSSascha Hauer 12276d38af25SUwe Kleine-König if (mtd->writesize) { 1228b8db2f51SSascha Hauer uint16_t pages_per_block = mtd->erasesize / mtd->writesize; 1229b8db2f51SSascha Hauer 12301f42adc8SUwe Kleine-König if (nand_chip->ecc.mode == NAND_ECC_HW) 12311f42adc8SUwe Kleine-König config1 |= NFC_V1_V2_CONFIG1_ECC_EN; 12321f42adc8SUwe Kleine-König 12336e85dfdcSSascha Hauer host->eccsize = get_eccsize(mtd); 12346e85dfdcSSascha Hauer if (host->eccsize == 4) 1235b8db2f51SSascha Hauer config1 |= NFC_V2_CONFIG1_ECC_MODE_4; 1236b8db2f51SSascha Hauer 1237b8db2f51SSascha Hauer config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6); 12386e85dfdcSSascha Hauer } else { 12396e85dfdcSSascha Hauer host->eccsize = 1; 12406e85dfdcSSascha Hauer } 12416e85dfdcSSascha Hauer 1242b8db2f51SSascha Hauer writew(config1, NFC_V1_V2_CONFIG1); 1243d4840180SIvo Clarysse /* preset operation */ 1244d4840180SIvo Clarysse 12453f77f244SMartin Kaiser /* spare area size in 16-bit half-words */ 12463f77f244SMartin Kaiser writew(mtd->oobsize / 2, NFC_V21_RSLTSPARE_AREA); 12473f77f244SMartin Kaiser 1248d4840180SIvo Clarysse /* Unlock the internal RAM Buffer */ 12491bc99180SSascha Hauer writew(0x2, NFC_V1_V2_CONFIG); 1250d4840180SIvo Clarysse 1251d4840180SIvo Clarysse /* Blocks to be unlocked */ 1252d178e3e8SBaruch Siach writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0); 1253d178e3e8SBaruch Siach writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1); 1254d178e3e8SBaruch Siach writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2); 1255d178e3e8SBaruch Siach writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3); 1256d178e3e8SBaruch Siach writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0); 1257d178e3e8SBaruch Siach writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1); 1258d178e3e8SBaruch Siach writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2); 1259d178e3e8SBaruch Siach writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3); 1260d4840180SIvo Clarysse 1261d4840180SIvo Clarysse /* Unlock Block Command for given address range */ 12621bc99180SSascha Hauer writew(0x4, NFC_V1_V2_WRPROT); 1263d4840180SIvo Clarysse } 1264d4840180SIvo Clarysse 126571ec5155SSascha Hauer static void preset_v3(struct mtd_info *mtd) 126671ec5155SSascha Hauer { 12674bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 1268d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(chip); 126971ec5155SSascha Hauer uint32_t config2, config3; 127071ec5155SSascha Hauer int i, addr_phases; 127171ec5155SSascha Hauer 127271ec5155SSascha Hauer writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1); 127371ec5155SSascha Hauer writel(NFC_V3_IPC_CREQ, NFC_V3_IPC); 127471ec5155SSascha Hauer 127571ec5155SSascha Hauer /* Unlock the internal RAM Buffer */ 127671ec5155SSascha Hauer writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK, 127771ec5155SSascha Hauer NFC_V3_WRPROT); 127871ec5155SSascha Hauer 127971ec5155SSascha Hauer /* Blocks to be unlocked */ 128071ec5155SSascha Hauer for (i = 0; i < NAND_MAX_CHIPS; i++) 12811b15b1f5SFabio Estevam writel(0xffff << 16, NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2)); 128271ec5155SSascha Hauer 128371ec5155SSascha Hauer writel(0, NFC_V3_IPC); 128471ec5155SSascha Hauer 128571ec5155SSascha Hauer config2 = NFC_V3_CONFIG2_ONE_CYCLE | 128671ec5155SSascha Hauer NFC_V3_CONFIG2_2CMD_PHASES | 128771ec5155SSascha Hauer NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) | 128871ec5155SSascha Hauer NFC_V3_CONFIG2_ST_CMD(0x70) | 128963f1474cSSascha Hauer NFC_V3_CONFIG2_INT_MSK | 129071ec5155SSascha Hauer NFC_V3_CONFIG2_NUM_ADDR_PHASE0; 129171ec5155SSascha Hauer 129271ec5155SSascha Hauer addr_phases = fls(chip->pagemask) >> 3; 129371ec5155SSascha Hauer 129471ec5155SSascha Hauer if (mtd->writesize == 2048) { 129571ec5155SSascha Hauer config2 |= NFC_V3_CONFIG2_PS_2048; 129671ec5155SSascha Hauer config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases); 129771ec5155SSascha Hauer } else if (mtd->writesize == 4096) { 129871ec5155SSascha Hauer config2 |= NFC_V3_CONFIG2_PS_4096; 129971ec5155SSascha Hauer config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases); 130071ec5155SSascha Hauer } else { 130171ec5155SSascha Hauer config2 |= NFC_V3_CONFIG2_PS_512; 130271ec5155SSascha Hauer config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1); 130371ec5155SSascha Hauer } 130471ec5155SSascha Hauer 130571ec5155SSascha Hauer if (mtd->writesize) { 13061f42adc8SUwe Kleine-König if (chip->ecc.mode == NAND_ECC_HW) 13071f42adc8SUwe Kleine-König config2 |= NFC_V3_CONFIG2_ECC_EN; 13081f42adc8SUwe Kleine-König 130971718a8eSSascha Hauer config2 |= NFC_V3_CONFIG2_PPB( 131071718a8eSSascha Hauer ffs(mtd->erasesize / mtd->writesize) - 6, 131171718a8eSSascha Hauer host->devtype_data->ppb_shift); 131271ec5155SSascha Hauer host->eccsize = get_eccsize(mtd); 131371ec5155SSascha Hauer if (host->eccsize == 8) 131471ec5155SSascha Hauer config2 |= NFC_V3_CONFIG2_ECC_MODE_8; 131571ec5155SSascha Hauer } 131671ec5155SSascha Hauer 131771ec5155SSascha Hauer writel(config2, NFC_V3_CONFIG2); 131871ec5155SSascha Hauer 131971ec5155SSascha Hauer config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) | 132071ec5155SSascha Hauer NFC_V3_CONFIG3_NO_SDMA | 132171ec5155SSascha Hauer NFC_V3_CONFIG3_RBB_MODE | 132271ec5155SSascha Hauer NFC_V3_CONFIG3_SBB(6) | /* Reset default */ 132371ec5155SSascha Hauer NFC_V3_CONFIG3_ADD_OP(0); 132471ec5155SSascha Hauer 132571ec5155SSascha Hauer if (!(chip->options & NAND_BUSWIDTH_16)) 132671ec5155SSascha Hauer config3 |= NFC_V3_CONFIG3_FW8; 132771ec5155SSascha Hauer 132871ec5155SSascha Hauer writel(config3, NFC_V3_CONFIG3); 132971ec5155SSascha Hauer 133071ec5155SSascha Hauer writel(0, NFC_V3_DELAY_LINE); 1331a3e65b64SSascha Hauer } 133234f6e157SSascha Hauer 133334f6e157SSascha Hauer /* Used by the upper layer to write command to NAND Flash for 133434f6e157SSascha Hauer * different operations to be carried out on NAND Flash */ 13355295cf2eSBoris Brezillon static void mxc_nand_command(struct nand_chip *nand_chip, unsigned command, 133634f6e157SSascha Hauer int column, int page_addr) 133734f6e157SSascha Hauer { 13385295cf2eSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(nand_chip); 1339d699ed25SBoris BREZILLON struct mxc_nand_host *host = nand_get_controller_data(nand_chip); 134034f6e157SSascha Hauer 13411f3df4dcSSascha Hauer dev_dbg(host->dev, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", 134234f6e157SSascha Hauer command, column, page_addr); 134334f6e157SSascha Hauer 134434f6e157SSascha Hauer /* Reset command state information */ 134534f6e157SSascha Hauer host->status_request = false; 134634f6e157SSascha Hauer 134734f6e157SSascha Hauer /* Command pre-processing step */ 134834f6e157SSascha Hauer switch (command) { 1349d4840180SIvo Clarysse case NAND_CMD_RESET: 1350e4303b25SUwe Kleine-König host->devtype_data->preset(mtd); 1351e4303b25SUwe Kleine-König host->devtype_data->send_cmd(host, command, false); 1352d4840180SIvo Clarysse break; 135334f6e157SSascha Hauer 135434f6e157SSascha Hauer case NAND_CMD_STATUS: 1355f8f9608dSSascha Hauer host->buf_start = 0; 135634f6e157SSascha Hauer host->status_request = true; 135789121a6bSSascha Hauer 1358e4303b25SUwe Kleine-König host->devtype_data->send_cmd(host, command, true); 1359c4ca3997SUwe Kleine-König WARN_ONCE(column != -1 || page_addr != -1, 1360c4ca3997SUwe Kleine-König "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", 1361c4ca3997SUwe Kleine-König command, column, page_addr); 136289121a6bSSascha Hauer mxc_do_addr_cycle(mtd, column, page_addr); 136334f6e157SSascha Hauer break; 136434f6e157SSascha Hauer 136534f6e157SSascha Hauer case NAND_CMD_READID: 1366e4303b25SUwe Kleine-König host->devtype_data->send_cmd(host, command, true); 136789121a6bSSascha Hauer mxc_do_addr_cycle(mtd, column, page_addr); 1368e4303b25SUwe Kleine-König host->devtype_data->send_read_id(host); 1369c4ca3997SUwe Kleine-König host->buf_start = 0; 137034f6e157SSascha Hauer break; 137134f6e157SSascha Hauer 137289121a6bSSascha Hauer case NAND_CMD_ERASE1: 137334f6e157SSascha Hauer case NAND_CMD_ERASE2: 1374e4303b25SUwe Kleine-König host->devtype_data->send_cmd(host, command, false); 1375c4ca3997SUwe Kleine-König WARN_ONCE(column != -1, 1376c4ca3997SUwe Kleine-König "Unexpected column value (cmd=%u, col=%d)\n", 1377c4ca3997SUwe Kleine-König command, column); 137889121a6bSSascha Hauer mxc_do_addr_cycle(mtd, column, page_addr); 137989121a6bSSascha Hauer 138034f6e157SSascha Hauer break; 13813d6e81c0SUwe Kleine-König case NAND_CMD_PARAM: 13823d6e81c0SUwe Kleine-König host->devtype_data->send_cmd(host, command, false); 13833d6e81c0SUwe Kleine-König mxc_do_addr_cycle(mtd, column, page_addr); 13843d6e81c0SUwe Kleine-König host->devtype_data->send_page(mtd, NFC_OUTPUT); 13853d6e81c0SUwe Kleine-König memcpy32_fromio(host->data_buf, host->main_area0, 512); 13863d6e81c0SUwe Kleine-König host->buf_start = 0; 13873d6e81c0SUwe Kleine-König break; 138898ebb521SUwe Kleine-König default: 138998ebb521SUwe Kleine-König WARN_ONCE(1, "Unimplemented command (cmd=%u)\n", 139098ebb521SUwe Kleine-König command); 139198ebb521SUwe Kleine-König break; 139234f6e157SSascha Hauer } 139334f6e157SSascha Hauer } 139434f6e157SSascha Hauer 1395aa36ff25SBoris Brezillon static int mxc_nand_set_features(struct nand_chip *chip, int addr, 1396aa36ff25SBoris Brezillon u8 *subfeature_param) 13974123ea34SSascha Hauer { 1398aa36ff25SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 1399aa36ff25SBoris Brezillon struct mxc_nand_host *host = nand_get_controller_data(chip); 14004123ea34SSascha Hauer int i; 14014123ea34SSascha Hauer 14024123ea34SSascha Hauer host->buf_start = 0; 14034123ea34SSascha Hauer 14044123ea34SSascha Hauer for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) 1405716bbbabSBoris Brezillon chip->legacy.write_byte(chip, subfeature_param[i]); 14064123ea34SSascha Hauer 14074123ea34SSascha Hauer memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize); 14084123ea34SSascha Hauer host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false); 14094123ea34SSascha Hauer mxc_do_addr_cycle(mtd, addr, -1); 14104123ea34SSascha Hauer host->devtype_data->send_page(mtd, NFC_INPUT); 14114123ea34SSascha Hauer 14124123ea34SSascha Hauer return 0; 14134123ea34SSascha Hauer } 14144123ea34SSascha Hauer 1415aa36ff25SBoris Brezillon static int mxc_nand_get_features(struct nand_chip *chip, int addr, 1416aa36ff25SBoris Brezillon u8 *subfeature_param) 14174123ea34SSascha Hauer { 1418aa36ff25SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 1419aa36ff25SBoris Brezillon struct mxc_nand_host *host = nand_get_controller_data(chip); 14204123ea34SSascha Hauer int i; 14214123ea34SSascha Hauer 14224123ea34SSascha Hauer host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false); 14234123ea34SSascha Hauer mxc_do_addr_cycle(mtd, addr, -1); 14244123ea34SSascha Hauer host->devtype_data->send_page(mtd, NFC_OUTPUT); 14254123ea34SSascha Hauer memcpy32_fromio(host->data_buf, host->main_area0, 512); 14264123ea34SSascha Hauer host->buf_start = 0; 14274123ea34SSascha Hauer 14284123ea34SSascha Hauer for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) 1429716bbbabSBoris Brezillon *subfeature_param++ = chip->legacy.read_byte(chip); 14304123ea34SSascha Hauer 14314123ea34SSascha Hauer return 0; 14324123ea34SSascha Hauer } 14334123ea34SSascha Hauer 1434f1372055SSascha Hauer /* 1435f1372055SSascha Hauer * The generic flash bbt decriptors overlap with our ecc 1436f1372055SSascha Hauer * hardware, so define some i.MX specific ones. 1437f1372055SSascha Hauer */ 1438f1372055SSascha Hauer static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; 1439f1372055SSascha Hauer static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; 1440f1372055SSascha Hauer 1441f1372055SSascha Hauer static struct nand_bbt_descr bbt_main_descr = { 1442f1372055SSascha Hauer .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE 1443f1372055SSascha Hauer | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, 1444f1372055SSascha Hauer .offs = 0, 1445f1372055SSascha Hauer .len = 4, 1446f1372055SSascha Hauer .veroffs = 4, 1447f1372055SSascha Hauer .maxblocks = 4, 1448f1372055SSascha Hauer .pattern = bbt_pattern, 1449f1372055SSascha Hauer }; 1450f1372055SSascha Hauer 1451f1372055SSascha Hauer static struct nand_bbt_descr bbt_mirror_descr = { 1452f1372055SSascha Hauer .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE 1453f1372055SSascha Hauer | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, 1454f1372055SSascha Hauer .offs = 0, 1455f1372055SSascha Hauer .len = 4, 1456f1372055SSascha Hauer .veroffs = 4, 1457f1372055SSascha Hauer .maxblocks = 4, 1458f1372055SSascha Hauer .pattern = mirror_pattern, 1459f1372055SSascha Hauer }; 1460f1372055SSascha Hauer 1461f48d0f9aSUwe Kleine-König /* v1 + irqpending_quirk: i.MX21 */ 1462e4303b25SUwe Kleine-König static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { 14636d38af25SUwe Kleine-König .preset = preset_v1, 14645039fc9fSSascha Hauer .read_page = mxc_nand_read_page_v1, 1465e4303b25SUwe Kleine-König .send_cmd = send_cmd_v1_v2, 1466e4303b25SUwe Kleine-König .send_addr = send_addr_v1_v2, 14676d38af25SUwe Kleine-König .send_page = send_page_v1, 1468e4303b25SUwe Kleine-König .send_read_id = send_read_id_v1_v2, 1469e4303b25SUwe Kleine-König .get_dev_status = get_dev_status_v1_v2, 1470e4303b25SUwe Kleine-König .check_int = check_int_v1_v2, 1471e4303b25SUwe Kleine-König .irq_control = irq_control_v1_v2, 14726d38af25SUwe Kleine-König .get_ecc_status = get_ecc_status_v1, 1473a894cf6cSBoris Brezillon .ooblayout = &mxc_v1_ooblayout_ops, 14745e05a2d6SUwe Kleine-König .select_chip = mxc_nand_select_chip_v1_v3, 1475040bd3f6SSascha Hauer .enable_hwecc = mxc_nand_enable_hwecc_v1_v2, 1476f48d0f9aSUwe Kleine-König .irqpending_quirk = 1, 1477f48d0f9aSUwe Kleine-König .needs_ip = 0, 1478f48d0f9aSUwe Kleine-König .regs_offset = 0xe00, 1479f48d0f9aSUwe Kleine-König .spare0_offset = 0x800, 1480f48d0f9aSUwe Kleine-König .spare_len = 16, 1481f48d0f9aSUwe Kleine-König .eccbytes = 3, 1482f48d0f9aSUwe Kleine-König .eccsize = 1, 1483f48d0f9aSUwe Kleine-König }; 1484f48d0f9aSUwe Kleine-König 1485f48d0f9aSUwe Kleine-König /* v1 + !irqpending_quirk: i.MX27, i.MX31 */ 1486f48d0f9aSUwe Kleine-König static const struct mxc_nand_devtype_data imx27_nand_devtype_data = { 1487f48d0f9aSUwe Kleine-König .preset = preset_v1, 14885039fc9fSSascha Hauer .read_page = mxc_nand_read_page_v1, 1489f48d0f9aSUwe Kleine-König .send_cmd = send_cmd_v1_v2, 1490f48d0f9aSUwe Kleine-König .send_addr = send_addr_v1_v2, 1491f48d0f9aSUwe Kleine-König .send_page = send_page_v1, 1492f48d0f9aSUwe Kleine-König .send_read_id = send_read_id_v1_v2, 1493f48d0f9aSUwe Kleine-König .get_dev_status = get_dev_status_v1_v2, 1494f48d0f9aSUwe Kleine-König .check_int = check_int_v1_v2, 1495f48d0f9aSUwe Kleine-König .irq_control = irq_control_v1_v2, 1496f48d0f9aSUwe Kleine-König .get_ecc_status = get_ecc_status_v1, 1497a894cf6cSBoris Brezillon .ooblayout = &mxc_v1_ooblayout_ops, 1498f48d0f9aSUwe Kleine-König .select_chip = mxc_nand_select_chip_v1_v3, 1499040bd3f6SSascha Hauer .enable_hwecc = mxc_nand_enable_hwecc_v1_v2, 1500f48d0f9aSUwe Kleine-König .irqpending_quirk = 0, 1501f48d0f9aSUwe Kleine-König .needs_ip = 0, 1502f48d0f9aSUwe Kleine-König .regs_offset = 0xe00, 1503f48d0f9aSUwe Kleine-König .spare0_offset = 0x800, 1504f48d0f9aSUwe Kleine-König .axi_offset = 0, 1505f48d0f9aSUwe Kleine-König .spare_len = 16, 1506f48d0f9aSUwe Kleine-König .eccbytes = 3, 1507f48d0f9aSUwe Kleine-König .eccsize = 1, 1508e4303b25SUwe Kleine-König }; 1509e4303b25SUwe Kleine-König 1510e4303b25SUwe Kleine-König /* v21: i.MX25, i.MX35 */ 1511e4303b25SUwe Kleine-König static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { 15126d38af25SUwe Kleine-König .preset = preset_v2, 151367b87f66SSascha Hauer .read_page = mxc_nand_read_page_v2_v3, 1514e4303b25SUwe Kleine-König .send_cmd = send_cmd_v1_v2, 1515e4303b25SUwe Kleine-König .send_addr = send_addr_v1_v2, 15166d38af25SUwe Kleine-König .send_page = send_page_v2, 1517e4303b25SUwe Kleine-König .send_read_id = send_read_id_v1_v2, 1518e4303b25SUwe Kleine-König .get_dev_status = get_dev_status_v1_v2, 1519e4303b25SUwe Kleine-König .check_int = check_int_v1_v2, 1520e4303b25SUwe Kleine-König .irq_control = irq_control_v1_v2, 15216d38af25SUwe Kleine-König .get_ecc_status = get_ecc_status_v2, 1522a894cf6cSBoris Brezillon .ooblayout = &mxc_v2_ooblayout_ops, 15235e05a2d6SUwe Kleine-König .select_chip = mxc_nand_select_chip_v2, 152482830796SSascha Hauer .setup_data_interface = mxc_nand_v2_setup_data_interface, 1525040bd3f6SSascha Hauer .enable_hwecc = mxc_nand_enable_hwecc_v1_v2, 1526f48d0f9aSUwe Kleine-König .irqpending_quirk = 0, 1527f48d0f9aSUwe Kleine-König .needs_ip = 0, 1528f48d0f9aSUwe Kleine-König .regs_offset = 0x1e00, 1529f48d0f9aSUwe Kleine-König .spare0_offset = 0x1000, 1530f48d0f9aSUwe Kleine-König .axi_offset = 0, 1531f48d0f9aSUwe Kleine-König .spare_len = 64, 1532f48d0f9aSUwe Kleine-König .eccbytes = 9, 1533f48d0f9aSUwe Kleine-König .eccsize = 0, 1534e4303b25SUwe Kleine-König }; 1535e4303b25SUwe Kleine-König 153671718a8eSSascha Hauer /* v3.2a: i.MX51 */ 1537e4303b25SUwe Kleine-König static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { 1538e4303b25SUwe Kleine-König .preset = preset_v3, 153967b87f66SSascha Hauer .read_page = mxc_nand_read_page_v2_v3, 1540e4303b25SUwe Kleine-König .send_cmd = send_cmd_v3, 1541e4303b25SUwe Kleine-König .send_addr = send_addr_v3, 1542e4303b25SUwe Kleine-König .send_page = send_page_v3, 1543e4303b25SUwe Kleine-König .send_read_id = send_read_id_v3, 1544e4303b25SUwe Kleine-König .get_dev_status = get_dev_status_v3, 1545e4303b25SUwe Kleine-König .check_int = check_int_v3, 1546e4303b25SUwe Kleine-König .irq_control = irq_control_v3, 15476d38af25SUwe Kleine-König .get_ecc_status = get_ecc_status_v3, 1548a894cf6cSBoris Brezillon .ooblayout = &mxc_v2_ooblayout_ops, 15495e05a2d6SUwe Kleine-König .select_chip = mxc_nand_select_chip_v1_v3, 1550040bd3f6SSascha Hauer .enable_hwecc = mxc_nand_enable_hwecc_v3, 1551f48d0f9aSUwe Kleine-König .irqpending_quirk = 0, 1552f48d0f9aSUwe Kleine-König .needs_ip = 1, 1553f48d0f9aSUwe Kleine-König .regs_offset = 0, 1554f48d0f9aSUwe Kleine-König .spare0_offset = 0x1000, 1555f48d0f9aSUwe Kleine-König .axi_offset = 0x1e00, 1556f48d0f9aSUwe Kleine-König .spare_len = 64, 1557f48d0f9aSUwe Kleine-König .eccbytes = 0, 1558f48d0f9aSUwe Kleine-König .eccsize = 0, 155971718a8eSSascha Hauer .ppb_shift = 7, 156071718a8eSSascha Hauer }; 156171718a8eSSascha Hauer 156271718a8eSSascha Hauer /* v3.2b: i.MX53 */ 156371718a8eSSascha Hauer static const struct mxc_nand_devtype_data imx53_nand_devtype_data = { 156471718a8eSSascha Hauer .preset = preset_v3, 156567b87f66SSascha Hauer .read_page = mxc_nand_read_page_v2_v3, 156671718a8eSSascha Hauer .send_cmd = send_cmd_v3, 156771718a8eSSascha Hauer .send_addr = send_addr_v3, 156871718a8eSSascha Hauer .send_page = send_page_v3, 156971718a8eSSascha Hauer .send_read_id = send_read_id_v3, 157071718a8eSSascha Hauer .get_dev_status = get_dev_status_v3, 157171718a8eSSascha Hauer .check_int = check_int_v3, 157271718a8eSSascha Hauer .irq_control = irq_control_v3, 157371718a8eSSascha Hauer .get_ecc_status = get_ecc_status_v3, 1574a894cf6cSBoris Brezillon .ooblayout = &mxc_v2_ooblayout_ops, 157571718a8eSSascha Hauer .select_chip = mxc_nand_select_chip_v1_v3, 1576040bd3f6SSascha Hauer .enable_hwecc = mxc_nand_enable_hwecc_v3, 157771718a8eSSascha Hauer .irqpending_quirk = 0, 157871718a8eSSascha Hauer .needs_ip = 1, 157971718a8eSSascha Hauer .regs_offset = 0, 158071718a8eSSascha Hauer .spare0_offset = 0x1000, 158171718a8eSSascha Hauer .axi_offset = 0x1e00, 158271718a8eSSascha Hauer .spare_len = 64, 158371718a8eSSascha Hauer .eccbytes = 0, 158471718a8eSSascha Hauer .eccsize = 0, 158571718a8eSSascha Hauer .ppb_shift = 8, 1586e4303b25SUwe Kleine-König }; 1587e4303b25SUwe Kleine-König 15884d62435fSShawn Guo static inline int is_imx21_nfc(struct mxc_nand_host *host) 15894d62435fSShawn Guo { 15904d62435fSShawn Guo return host->devtype_data == &imx21_nand_devtype_data; 15914d62435fSShawn Guo } 15924d62435fSShawn Guo 15934d62435fSShawn Guo static inline int is_imx27_nfc(struct mxc_nand_host *host) 15944d62435fSShawn Guo { 15954d62435fSShawn Guo return host->devtype_data == &imx27_nand_devtype_data; 15964d62435fSShawn Guo } 15974d62435fSShawn Guo 15984d62435fSShawn Guo static inline int is_imx25_nfc(struct mxc_nand_host *host) 15994d62435fSShawn Guo { 16004d62435fSShawn Guo return host->devtype_data == &imx25_nand_devtype_data; 16014d62435fSShawn Guo } 16024d62435fSShawn Guo 16034d62435fSShawn Guo static inline int is_imx51_nfc(struct mxc_nand_host *host) 16044d62435fSShawn Guo { 16054d62435fSShawn Guo return host->devtype_data == &imx51_nand_devtype_data; 16064d62435fSShawn Guo } 16074d62435fSShawn Guo 16084d62435fSShawn Guo static inline int is_imx53_nfc(struct mxc_nand_host *host) 16094d62435fSShawn Guo { 16104d62435fSShawn Guo return host->devtype_data == &imx53_nand_devtype_data; 16114d62435fSShawn Guo } 16124d62435fSShawn Guo 16138d1e568dSKrzysztof Kozlowski static const struct platform_device_id mxcnd_devtype[] = { 16144d62435fSShawn Guo { 16154d62435fSShawn Guo .name = "imx21-nand", 16164d62435fSShawn Guo .driver_data = (kernel_ulong_t) &imx21_nand_devtype_data, 16174d62435fSShawn Guo }, { 16184d62435fSShawn Guo .name = "imx27-nand", 16194d62435fSShawn Guo .driver_data = (kernel_ulong_t) &imx27_nand_devtype_data, 16204d62435fSShawn Guo }, { 16214d62435fSShawn Guo .name = "imx25-nand", 16224d62435fSShawn Guo .driver_data = (kernel_ulong_t) &imx25_nand_devtype_data, 16234d62435fSShawn Guo }, { 16244d62435fSShawn Guo .name = "imx51-nand", 16254d62435fSShawn Guo .driver_data = (kernel_ulong_t) &imx51_nand_devtype_data, 16264d62435fSShawn Guo }, { 16274d62435fSShawn Guo .name = "imx53-nand", 16284d62435fSShawn Guo .driver_data = (kernel_ulong_t) &imx53_nand_devtype_data, 16294d62435fSShawn Guo }, { 16304d62435fSShawn Guo /* sentinel */ 16314d62435fSShawn Guo } 16324d62435fSShawn Guo }; 16334d62435fSShawn Guo MODULE_DEVICE_TABLE(platform, mxcnd_devtype); 16344d62435fSShawn Guo 1635ba52b4ddSBoris Brezillon #ifdef CONFIG_OF 16366436356bSUwe Kleine-König static const struct of_device_id mxcnd_dt_ids[] = { 16376436356bSUwe Kleine-König { 16386436356bSUwe Kleine-König .compatible = "fsl,imx21-nand", 16396436356bSUwe Kleine-König .data = &imx21_nand_devtype_data, 16406436356bSUwe Kleine-König }, { 16416436356bSUwe Kleine-König .compatible = "fsl,imx27-nand", 16426436356bSUwe Kleine-König .data = &imx27_nand_devtype_data, 16436436356bSUwe Kleine-König }, { 16446436356bSUwe Kleine-König .compatible = "fsl,imx25-nand", 16456436356bSUwe Kleine-König .data = &imx25_nand_devtype_data, 16466436356bSUwe Kleine-König }, { 16476436356bSUwe Kleine-König .compatible = "fsl,imx51-nand", 16486436356bSUwe Kleine-König .data = &imx51_nand_devtype_data, 164971718a8eSSascha Hauer }, { 165071718a8eSSascha Hauer .compatible = "fsl,imx53-nand", 165171718a8eSSascha Hauer .data = &imx53_nand_devtype_data, 16526436356bSUwe Kleine-König }, 16536436356bSUwe Kleine-König { /* sentinel */ } 16546436356bSUwe Kleine-König }; 1655b33c35b1SLuis de Bethencourt MODULE_DEVICE_TABLE(of, mxcnd_dt_ids); 16566436356bSUwe Kleine-König 165724f0ae99SMartin Kaiser static int mxcnd_probe_dt(struct mxc_nand_host *host) 16586436356bSUwe Kleine-König { 16596436356bSUwe Kleine-König struct device_node *np = host->dev->of_node; 16606436356bSUwe Kleine-König const struct of_device_id *of_id = 16616436356bSUwe Kleine-König of_match_device(mxcnd_dt_ids, host->dev); 16626436356bSUwe Kleine-König 16636436356bSUwe Kleine-König if (!np) 16646436356bSUwe Kleine-König return 1; 16656436356bSUwe Kleine-König 16666436356bSUwe Kleine-König host->devtype_data = of_id->data; 16676436356bSUwe Kleine-König 16686436356bSUwe Kleine-König return 0; 16696436356bSUwe Kleine-König } 16706436356bSUwe Kleine-König #else 167124f0ae99SMartin Kaiser static int mxcnd_probe_dt(struct mxc_nand_host *host) 16726436356bSUwe Kleine-König { 16736436356bSUwe Kleine-König return 1; 16746436356bSUwe Kleine-König } 16756436356bSUwe Kleine-König #endif 16766436356bSUwe Kleine-König 167796fa8e6eSMiquel Raynal static int mxcnd_attach_chip(struct nand_chip *chip) 167896fa8e6eSMiquel Raynal { 167996fa8e6eSMiquel Raynal struct mtd_info *mtd = nand_to_mtd(chip); 168096fa8e6eSMiquel Raynal struct mxc_nand_host *host = nand_get_controller_data(chip); 168196fa8e6eSMiquel Raynal struct device *dev = mtd->dev.parent; 168296fa8e6eSMiquel Raynal 168396fa8e6eSMiquel Raynal switch (chip->ecc.mode) { 168496fa8e6eSMiquel Raynal case NAND_ECC_HW: 168596fa8e6eSMiquel Raynal chip->ecc.read_page = mxc_nand_read_page; 168696fa8e6eSMiquel Raynal chip->ecc.read_page_raw = mxc_nand_read_page_raw; 168796fa8e6eSMiquel Raynal chip->ecc.read_oob = mxc_nand_read_oob; 168896fa8e6eSMiquel Raynal chip->ecc.write_page = mxc_nand_write_page_ecc; 168996fa8e6eSMiquel Raynal chip->ecc.write_page_raw = mxc_nand_write_page_raw; 169096fa8e6eSMiquel Raynal chip->ecc.write_oob = mxc_nand_write_oob; 169196fa8e6eSMiquel Raynal break; 169296fa8e6eSMiquel Raynal 169396fa8e6eSMiquel Raynal case NAND_ECC_SOFT: 169496fa8e6eSMiquel Raynal break; 169596fa8e6eSMiquel Raynal 169696fa8e6eSMiquel Raynal default: 169796fa8e6eSMiquel Raynal return -EINVAL; 169896fa8e6eSMiquel Raynal } 169996fa8e6eSMiquel Raynal 170096fa8e6eSMiquel Raynal if (chip->bbt_options & NAND_BBT_USE_FLASH) { 170196fa8e6eSMiquel Raynal chip->bbt_td = &bbt_main_descr; 170296fa8e6eSMiquel Raynal chip->bbt_md = &bbt_mirror_descr; 170396fa8e6eSMiquel Raynal } 170496fa8e6eSMiquel Raynal 170596fa8e6eSMiquel Raynal /* Allocate the right size buffer now */ 170696fa8e6eSMiquel Raynal devm_kfree(dev, (void *)host->data_buf); 170796fa8e6eSMiquel Raynal host->data_buf = devm_kzalloc(dev, mtd->writesize + mtd->oobsize, 170896fa8e6eSMiquel Raynal GFP_KERNEL); 170996fa8e6eSMiquel Raynal if (!host->data_buf) 171096fa8e6eSMiquel Raynal return -ENOMEM; 171196fa8e6eSMiquel Raynal 171296fa8e6eSMiquel Raynal /* Call preset again, with correct writesize chip time */ 171396fa8e6eSMiquel Raynal host->devtype_data->preset(mtd); 171496fa8e6eSMiquel Raynal 171596fa8e6eSMiquel Raynal if (!chip->ecc.bytes) { 171696fa8e6eSMiquel Raynal if (host->eccsize == 8) 171796fa8e6eSMiquel Raynal chip->ecc.bytes = 18; 171896fa8e6eSMiquel Raynal else if (host->eccsize == 4) 171996fa8e6eSMiquel Raynal chip->ecc.bytes = 9; 172096fa8e6eSMiquel Raynal } 172196fa8e6eSMiquel Raynal 172296fa8e6eSMiquel Raynal /* 172396fa8e6eSMiquel Raynal * Experimentation shows that i.MX NFC can only handle up to 218 oob 172496fa8e6eSMiquel Raynal * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare() 172596fa8e6eSMiquel Raynal * into copying invalid data to/from the spare IO buffer, as this 172696fa8e6eSMiquel Raynal * might cause ECC data corruption when doing sub-page write to a 172796fa8e6eSMiquel Raynal * partially written page. 172896fa8e6eSMiquel Raynal */ 172996fa8e6eSMiquel Raynal host->used_oobsize = min(mtd->oobsize, 218U); 173096fa8e6eSMiquel Raynal 173196fa8e6eSMiquel Raynal if (chip->ecc.mode == NAND_ECC_HW) { 173296fa8e6eSMiquel Raynal if (is_imx21_nfc(host) || is_imx27_nfc(host)) 173396fa8e6eSMiquel Raynal chip->ecc.strength = 1; 173496fa8e6eSMiquel Raynal else 173596fa8e6eSMiquel Raynal chip->ecc.strength = (host->eccsize == 4) ? 4 : 8; 173696fa8e6eSMiquel Raynal } 173796fa8e6eSMiquel Raynal 173896fa8e6eSMiquel Raynal return 0; 173996fa8e6eSMiquel Raynal } 174096fa8e6eSMiquel Raynal 17417a08dbaeSBoris Brezillon static int mxcnd_setup_data_interface(struct nand_chip *chip, int chipnr, 17427a08dbaeSBoris Brezillon const struct nand_data_interface *conf) 17437a08dbaeSBoris Brezillon { 17447a08dbaeSBoris Brezillon struct mxc_nand_host *host = nand_get_controller_data(chip); 17457a08dbaeSBoris Brezillon 17467a08dbaeSBoris Brezillon return host->devtype_data->setup_data_interface(chip, chipnr, conf); 17477a08dbaeSBoris Brezillon } 17487a08dbaeSBoris Brezillon 174996fa8e6eSMiquel Raynal static const struct nand_controller_ops mxcnd_controller_ops = { 175096fa8e6eSMiquel Raynal .attach_chip = mxcnd_attach_chip, 17517a08dbaeSBoris Brezillon .setup_data_interface = mxcnd_setup_data_interface, 175296fa8e6eSMiquel Raynal }; 175396fa8e6eSMiquel Raynal 175406f25510SBill Pemberton static int mxcnd_probe(struct platform_device *pdev) 175534f6e157SSascha Hauer { 175634f6e157SSascha Hauer struct nand_chip *this; 175734f6e157SSascha Hauer struct mtd_info *mtd; 175834f6e157SSascha Hauer struct mxc_nand_host *host; 175934f6e157SSascha Hauer struct resource *res; 1760d4ed8f12SDmitry Eremin-Solenikov int err = 0; 176134f6e157SSascha Hauer 176234f6e157SSascha Hauer /* Allocate memory for MTD device structure and private data */ 1763a5900554SHuang Shijie host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host), 1764a5900554SHuang Shijie GFP_KERNEL); 176534f6e157SSascha Hauer if (!host) 176634f6e157SSascha Hauer return -ENOMEM; 176734f6e157SSascha Hauer 1768a5900554SHuang Shijie /* allocate a temporary buffer for the nand_scan_ident() */ 1769a5900554SHuang Shijie host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL); 1770a5900554SHuang Shijie if (!host->data_buf) 1771a5900554SHuang Shijie return -ENOMEM; 1772f8f9608dSSascha Hauer 177334f6e157SSascha Hauer host->dev = &pdev->dev; 177434f6e157SSascha Hauer /* structures must be linked */ 177534f6e157SSascha Hauer this = &host->nand; 1776a008deb1SBoris BREZILLON mtd = nand_to_mtd(this); 177787f39f04SDavid Brownell mtd->dev.parent = &pdev->dev; 17781fbff0a6SSascha Hauer mtd->name = DRIVER_NAME; 177934f6e157SSascha Hauer 178034f6e157SSascha Hauer /* 50 us command delay time */ 17813cece3abSBoris Brezillon this->legacy.chip_delay = 5; 178234f6e157SSascha Hauer 1783d699ed25SBoris BREZILLON nand_set_controller_data(this, host); 1784a61ae81aSBrian Norris nand_set_flash_node(this, pdev->dev.of_node), 17858395b753SBoris Brezillon this->legacy.dev_ready = mxc_nand_dev_ready; 1786bf6065c6SBoris Brezillon this->legacy.cmdfunc = mxc_nand_command; 1787716bbbabSBoris Brezillon this->legacy.read_byte = mxc_nand_read_byte; 1788716bbbabSBoris Brezillon this->legacy.write_buf = mxc_nand_write_buf; 1789716bbbabSBoris Brezillon this->legacy.read_buf = mxc_nand_read_buf; 179045240367SBoris Brezillon this->legacy.set_features = mxc_nand_set_features; 179145240367SBoris Brezillon this->legacy.get_features = mxc_nand_get_features; 179234f6e157SSascha Hauer 179324b82d3cSFabio Estevam host->clk = devm_clk_get(&pdev->dev, NULL); 1794e4a09cbfSSascha Hauer if (IS_ERR(host->clk)) 1795e4a09cbfSSascha Hauer return PTR_ERR(host->clk); 179634f6e157SSascha Hauer 179771885b65SSascha Hauer err = mxcnd_probe_dt(host); 17984d62435fSShawn Guo if (err > 0) { 1799453810b7SJingoo Han struct mxc_nand_platform_data *pdata = 1800453810b7SJingoo Han dev_get_platdata(&pdev->dev); 18014d62435fSShawn Guo if (pdata) { 18024d62435fSShawn Guo host->pdata = *pdata; 18034d62435fSShawn Guo host->devtype_data = (struct mxc_nand_devtype_data *) 18044d62435fSShawn Guo pdev->id_entry->driver_data; 18054d62435fSShawn Guo } else { 18064d62435fSShawn Guo err = -ENODEV; 18074d62435fSShawn Guo } 18084d62435fSShawn Guo } 180971885b65SSascha Hauer if (err < 0) 181071885b65SSascha Hauer return err; 181171885b65SSascha Hauer 18127a08dbaeSBoris Brezillon if (!host->devtype_data->setup_data_interface) 18137a08dbaeSBoris Brezillon this->options |= NAND_KEEP_TIMINGS; 181482830796SSascha Hauer 181571885b65SSascha Hauer if (host->devtype_data->needs_ip) { 181634f6e157SSascha Hauer res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1817b0de774cSThierry Reding host->regs_ip = devm_ioremap_resource(&pdev->dev, res); 1818b0de774cSThierry Reding if (IS_ERR(host->regs_ip)) 1819b0de774cSThierry Reding return PTR_ERR(host->regs_ip); 182071885b65SSascha Hauer 182171885b65SSascha Hauer res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 182271885b65SSascha Hauer } else { 182371885b65SSascha Hauer res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 182471885b65SSascha Hauer } 182571885b65SSascha Hauer 1826b0de774cSThierry Reding host->base = devm_ioremap_resource(&pdev->dev, res); 1827b0de774cSThierry Reding if (IS_ERR(host->base)) 1828b0de774cSThierry Reding return PTR_ERR(host->base); 182934f6e157SSascha Hauer 1830c6de7e1bSSascha Hauer host->main_area0 = host->base; 18319467114eSSascha Hauer 1832f48d0f9aSUwe Kleine-König if (host->devtype_data->regs_offset) 1833f48d0f9aSUwe Kleine-König host->regs = host->base + host->devtype_data->regs_offset; 1834f48d0f9aSUwe Kleine-König host->spare0 = host->base + host->devtype_data->spare0_offset; 1835f48d0f9aSUwe Kleine-König if (host->devtype_data->axi_offset) 1836f48d0f9aSUwe Kleine-König host->regs_axi = host->base + host->devtype_data->axi_offset; 1837f48d0f9aSUwe Kleine-König 1838f48d0f9aSUwe Kleine-König this->ecc.bytes = host->devtype_data->eccbytes; 1839f48d0f9aSUwe Kleine-König host->eccsize = host->devtype_data->eccsize; 1840f48d0f9aSUwe Kleine-König 18417d6c37e9SBoris Brezillon this->legacy.select_chip = host->devtype_data->select_chip; 1842f48d0f9aSUwe Kleine-König this->ecc.size = 512; 1843a894cf6cSBoris Brezillon mtd_set_ooblayout(mtd, host->devtype_data->ooblayout); 1844f48d0f9aSUwe Kleine-König 18456436356bSUwe Kleine-König if (host->pdata.hw_ecc) { 184613e1add1SSascha Hauer this->ecc.mode = NAND_ECC_HW; 184713e1add1SSascha Hauer } else { 184813e1add1SSascha Hauer this->ecc.mode = NAND_ECC_SOFT; 1849c1c7040eSRafał Miłecki this->ecc.algo = NAND_ECC_HAMMING; 185034f6e157SSascha Hauer } 185134f6e157SSascha Hauer 18526436356bSUwe Kleine-König /* NAND bus width determines access functions used by upper layer */ 18536436356bSUwe Kleine-König if (host->pdata.width == 2) 185434f6e157SSascha Hauer this->options |= NAND_BUSWIDTH_16; 185513e1add1SSascha Hauer 1856f1372055SSascha Hauer /* update flash based bbt */ 1857609468f9SBoris Brezillon if (host->pdata.flash_bbt) 1858bb9ebd4eSBrian Norris this->bbt_options |= NAND_BBT_USE_FLASH; 185934f6e157SSascha Hauer 186063f1474cSSascha Hauer init_completion(&host->op_completion); 1861d4840180SIvo Clarysse 1862d4840180SIvo Clarysse host->irq = platform_get_irq(pdev, 0); 186326fbf48bSFabio Estevam if (host->irq < 0) 186426fbf48bSFabio Estevam return host->irq; 1865d4840180SIvo Clarysse 186663f1474cSSascha Hauer /* 1867e4303b25SUwe Kleine-König * Use host->devtype_data->irq_control() here instead of irq_control() 1868e4303b25SUwe Kleine-König * because we must not disable_irq_nosync without having requested the 1869e4303b25SUwe Kleine-König * irq. 187063f1474cSSascha Hauer */ 1871e4303b25SUwe Kleine-König host->devtype_data->irq_control(host, 0); 187263f1474cSSascha Hauer 1873e4a09cbfSSascha Hauer err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq, 1874b1eb234fSMichael Opdenacker 0, DRIVER_NAME, host); 1875d4840180SIvo Clarysse if (err) 1876e4a09cbfSSascha Hauer return err; 1877e4a09cbfSSascha Hauer 1878dcedf628SFabio Estevam err = clk_prepare_enable(host->clk); 1879dcedf628SFabio Estevam if (err) 1880dcedf628SFabio Estevam return err; 1881e4a09cbfSSascha Hauer host->clk_act = 1; 1882d4840180SIvo Clarysse 188363f1474cSSascha Hauer /* 18848556958aSUwe Kleine-König * Now that we "own" the interrupt make sure the interrupt mask bit is 18858556958aSUwe Kleine-König * cleared on i.MX21. Otherwise we can't read the interrupt status bit 18868556958aSUwe Kleine-König * on this machine. 188763f1474cSSascha Hauer */ 1888f48d0f9aSUwe Kleine-König if (host->devtype_data->irqpending_quirk) { 18898556958aSUwe Kleine-König disable_irq_nosync(host->irq); 1890e4303b25SUwe Kleine-König host->devtype_data->irq_control(host, 1); 18918556958aSUwe Kleine-König } 189263f1474cSSascha Hauer 189396fa8e6eSMiquel Raynal /* Scan the NAND device */ 1894*7b6a9b28SBoris Brezillon this->legacy.dummy_controller.ops = &mxcnd_controller_ops; 189500ad378fSBoris Brezillon err = nand_scan(this, is_imx25_nfc(host) ? 4 : 1); 1896bc83c788SMasahiro Yamada if (err) 18974a43faf5SSascha Hauer goto escan; 18984a43faf5SSascha Hauer 189934f6e157SSascha Hauer /* Register the partitions */ 1900be051bf2SMiquel Raynal err = mtd_device_parse_register(mtd, part_probes, NULL, 19016436356bSUwe Kleine-König host->pdata.parts, 19026436356bSUwe Kleine-König host->pdata.nr_parts); 1903be051bf2SMiquel Raynal if (err) 1904be051bf2SMiquel Raynal goto cleanup_nand; 190534f6e157SSascha Hauer 190634f6e157SSascha Hauer platform_set_drvdata(pdev, host); 190734f6e157SSascha Hauer 190834f6e157SSascha Hauer return 0; 190934f6e157SSascha Hauer 1910be051bf2SMiquel Raynal cleanup_nand: 1911be051bf2SMiquel Raynal nand_cleanup(this); 191234f6e157SSascha Hauer escan: 1913c10d8ee3SLothar Waßmann if (host->clk_act) 1914e4a09cbfSSascha Hauer clk_disable_unprepare(host->clk); 191534f6e157SSascha Hauer 191634f6e157SSascha Hauer return err; 191734f6e157SSascha Hauer } 191834f6e157SSascha Hauer 1919810b7e06SBill Pemberton static int mxcnd_remove(struct platform_device *pdev) 192034f6e157SSascha Hauer { 192134f6e157SSascha Hauer struct mxc_nand_host *host = platform_get_drvdata(pdev); 192234f6e157SSascha Hauer 192359ac276fSBoris Brezillon nand_release(&host->nand); 19248bfd4f7fSWei Yongjun if (host->clk_act) 19258bfd4f7fSWei Yongjun clk_disable_unprepare(host->clk); 192634f6e157SSascha Hauer 192734f6e157SSascha Hauer return 0; 192834f6e157SSascha Hauer } 192934f6e157SSascha Hauer 193034f6e157SSascha Hauer static struct platform_driver mxcnd_driver = { 193134f6e157SSascha Hauer .driver = { 193234f6e157SSascha Hauer .name = DRIVER_NAME, 19336436356bSUwe Kleine-König .of_match_table = of_match_ptr(mxcnd_dt_ids), 193434f6e157SSascha Hauer }, 19354d62435fSShawn Guo .id_table = mxcnd_devtype, 1936ddf16d62SFabio Estevam .probe = mxcnd_probe, 19375153b88cSBill Pemberton .remove = mxcnd_remove, 193834f6e157SSascha Hauer }; 1939ddf16d62SFabio Estevam module_platform_driver(mxcnd_driver); 194034f6e157SSascha Hauer 194134f6e157SSascha Hauer MODULE_AUTHOR("Freescale Semiconductor, Inc."); 194234f6e157SSascha Hauer MODULE_DESCRIPTION("MXC NAND MTD driver"); 194334f6e157SSascha Hauer MODULE_LICENSE("GPL"); 1944