116216333SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2bb315f74SAnatolij Gustschin /* 3bb315f74SAnatolij Gustschin * Copyright 2004-2008 Freescale Semiconductor, Inc. 4bb315f74SAnatolij Gustschin * Copyright 2009 Semihalf. 5bb315f74SAnatolij Gustschin * 6bb315f74SAnatolij Gustschin * Approved as OSADL project by a majority of OSADL members and funded 7bb315f74SAnatolij Gustschin * by OSADL membership fees in 2009; for details see www.osadl.org. 8bb315f74SAnatolij Gustschin * 9bb315f74SAnatolij Gustschin * Based on original driver from Freescale Semiconductor 1093cbd6f3SBoris Brezillon * written by John Rigby <jrigby@freescale.com> on basis of mxc_nand.c. 1193cbd6f3SBoris Brezillon * Reworked and extended by Piotr Ziecik <kosmo@semihalf.com>. 12bb315f74SAnatolij Gustschin */ 13bb315f74SAnatolij Gustschin 14bb315f74SAnatolij Gustschin #include <linux/module.h> 15bb315f74SAnatolij Gustschin #include <linux/clk.h> 1605d71b46STejun Heo #include <linux/gfp.h> 17bb315f74SAnatolij Gustschin #include <linux/delay.h> 1883025c82SJamie Iles #include <linux/err.h> 19bb315f74SAnatolij Gustschin #include <linux/interrupt.h> 20bb315f74SAnatolij Gustschin #include <linux/io.h> 21bb315f74SAnatolij Gustschin #include <linux/mtd/mtd.h> 22d4092d76SBoris Brezillon #include <linux/mtd/rawnand.h> 23bb315f74SAnatolij Gustschin #include <linux/mtd/partitions.h> 245af50730SRob Herring #include <linux/of_address.h> 25bb315f74SAnatolij Gustschin #include <linux/of_device.h> 265af50730SRob Herring #include <linux/of_irq.h> 27bb315f74SAnatolij Gustschin #include <linux/of_platform.h> 28bb315f74SAnatolij Gustschin 29bb315f74SAnatolij Gustschin #include <asm/mpc5121.h> 30bb315f74SAnatolij Gustschin 31bb315f74SAnatolij Gustschin /* Addresses for NFC MAIN RAM BUFFER areas */ 32bb315f74SAnatolij Gustschin #define NFC_MAIN_AREA(n) ((n) * 0x200) 33bb315f74SAnatolij Gustschin 34bb315f74SAnatolij Gustschin /* Addresses for NFC SPARE BUFFER areas */ 35bb315f74SAnatolij Gustschin #define NFC_SPARE_BUFFERS 8 36bb315f74SAnatolij Gustschin #define NFC_SPARE_LEN 0x40 37bb315f74SAnatolij Gustschin #define NFC_SPARE_AREA(n) (0x1000 + ((n) * NFC_SPARE_LEN)) 38bb315f74SAnatolij Gustschin 39bb315f74SAnatolij Gustschin /* MPC5121 NFC registers */ 40bb315f74SAnatolij Gustschin #define NFC_BUF_ADDR 0x1E04 41bb315f74SAnatolij Gustschin #define NFC_FLASH_ADDR 0x1E06 42bb315f74SAnatolij Gustschin #define NFC_FLASH_CMD 0x1E08 43bb315f74SAnatolij Gustschin #define NFC_CONFIG 0x1E0A 44bb315f74SAnatolij Gustschin #define NFC_ECC_STATUS1 0x1E0C 45bb315f74SAnatolij Gustschin #define NFC_ECC_STATUS2 0x1E0E 46bb315f74SAnatolij Gustschin #define NFC_SPAS 0x1E10 47bb315f74SAnatolij Gustschin #define NFC_WRPROT 0x1E12 48bb315f74SAnatolij Gustschin #define NFC_NF_WRPRST 0x1E18 49bb315f74SAnatolij Gustschin #define NFC_CONFIG1 0x1E1A 50bb315f74SAnatolij Gustschin #define NFC_CONFIG2 0x1E1C 51bb315f74SAnatolij Gustschin #define NFC_UNLOCKSTART_BLK0 0x1E20 52bb315f74SAnatolij Gustschin #define NFC_UNLOCKEND_BLK0 0x1E22 53bb315f74SAnatolij Gustschin #define NFC_UNLOCKSTART_BLK1 0x1E24 54bb315f74SAnatolij Gustschin #define NFC_UNLOCKEND_BLK1 0x1E26 55bb315f74SAnatolij Gustschin #define NFC_UNLOCKSTART_BLK2 0x1E28 56bb315f74SAnatolij Gustschin #define NFC_UNLOCKEND_BLK2 0x1E2A 57bb315f74SAnatolij Gustschin #define NFC_UNLOCKSTART_BLK3 0x1E2C 58bb315f74SAnatolij Gustschin #define NFC_UNLOCKEND_BLK3 0x1E2E 59bb315f74SAnatolij Gustschin 60bb315f74SAnatolij Gustschin /* Bit Definitions: NFC_BUF_ADDR */ 61bb315f74SAnatolij Gustschin #define NFC_RBA_MASK (7 << 0) 62bb315f74SAnatolij Gustschin #define NFC_ACTIVE_CS_SHIFT 5 63bb315f74SAnatolij Gustschin #define NFC_ACTIVE_CS_MASK (3 << NFC_ACTIVE_CS_SHIFT) 64bb315f74SAnatolij Gustschin 65bb315f74SAnatolij Gustschin /* Bit Definitions: NFC_CONFIG */ 66bb315f74SAnatolij Gustschin #define NFC_BLS_UNLOCKED (1 << 1) 67bb315f74SAnatolij Gustschin 68bb315f74SAnatolij Gustschin /* Bit Definitions: NFC_CONFIG1 */ 69bb315f74SAnatolij Gustschin #define NFC_ECC_4BIT (1 << 0) 70bb315f74SAnatolij Gustschin #define NFC_FULL_PAGE_DMA (1 << 1) 71bb315f74SAnatolij Gustschin #define NFC_SPARE_ONLY (1 << 2) 72bb315f74SAnatolij Gustschin #define NFC_ECC_ENABLE (1 << 3) 73bb315f74SAnatolij Gustschin #define NFC_INT_MASK (1 << 4) 74bb315f74SAnatolij Gustschin #define NFC_BIG_ENDIAN (1 << 5) 75bb315f74SAnatolij Gustschin #define NFC_RESET (1 << 6) 76bb315f74SAnatolij Gustschin #define NFC_CE (1 << 7) 77bb315f74SAnatolij Gustschin #define NFC_ONE_CYCLE (1 << 8) 78bb315f74SAnatolij Gustschin #define NFC_PPB_32 (0 << 9) 79bb315f74SAnatolij Gustschin #define NFC_PPB_64 (1 << 9) 80bb315f74SAnatolij Gustschin #define NFC_PPB_128 (2 << 9) 81bb315f74SAnatolij Gustschin #define NFC_PPB_256 (3 << 9) 82bb315f74SAnatolij Gustschin #define NFC_PPB_MASK (3 << 9) 83bb315f74SAnatolij Gustschin #define NFC_FULL_PAGE_INT (1 << 11) 84bb315f74SAnatolij Gustschin 85bb315f74SAnatolij Gustschin /* Bit Definitions: NFC_CONFIG2 */ 86bb315f74SAnatolij Gustschin #define NFC_COMMAND (1 << 0) 87bb315f74SAnatolij Gustschin #define NFC_ADDRESS (1 << 1) 88bb315f74SAnatolij Gustschin #define NFC_INPUT (1 << 2) 89bb315f74SAnatolij Gustschin #define NFC_OUTPUT (1 << 3) 90bb315f74SAnatolij Gustschin #define NFC_ID (1 << 4) 91bb315f74SAnatolij Gustschin #define NFC_STATUS (1 << 5) 92bb315f74SAnatolij Gustschin #define NFC_CMD_FAIL (1 << 15) 93bb315f74SAnatolij Gustschin #define NFC_INT (1 << 15) 94bb315f74SAnatolij Gustschin 95bb315f74SAnatolij Gustschin /* Bit Definitions: NFC_WRPROT */ 96bb315f74SAnatolij Gustschin #define NFC_WPC_LOCK_TIGHT (1 << 0) 97bb315f74SAnatolij Gustschin #define NFC_WPC_LOCK (1 << 1) 98bb315f74SAnatolij Gustschin #define NFC_WPC_UNLOCK (1 << 2) 99bb315f74SAnatolij Gustschin 100bb315f74SAnatolij Gustschin #define DRV_NAME "mpc5121_nfc" 101bb315f74SAnatolij Gustschin 102bb315f74SAnatolij Gustschin /* Timeouts */ 103bb315f74SAnatolij Gustschin #define NFC_RESET_TIMEOUT 1000 /* 1 ms */ 104bb315f74SAnatolij Gustschin #define NFC_TIMEOUT (HZ / 10) /* 1/10 s */ 105bb315f74SAnatolij Gustschin 106bb315f74SAnatolij Gustschin struct mpc5121_nfc_prv { 107bb315f74SAnatolij Gustschin struct nand_chip chip; 108bb315f74SAnatolij Gustschin int irq; 109bb315f74SAnatolij Gustschin void __iomem *regs; 110bb315f74SAnatolij Gustschin struct clk *clk; 111bb315f74SAnatolij Gustschin wait_queue_head_t irq_waitq; 112bb315f74SAnatolij Gustschin uint column; 113bb315f74SAnatolij Gustschin int spareonly; 114bb315f74SAnatolij Gustschin void __iomem *csreg; 115bb315f74SAnatolij Gustschin struct device *dev; 116bb315f74SAnatolij Gustschin }; 117bb315f74SAnatolij Gustschin 118bb315f74SAnatolij Gustschin static void mpc5121_nfc_done(struct mtd_info *mtd); 119bb315f74SAnatolij Gustschin 120bb315f74SAnatolij Gustschin /* Read NFC register */ 121bb315f74SAnatolij Gustschin static inline u16 nfc_read(struct mtd_info *mtd, uint reg) 122bb315f74SAnatolij Gustschin { 1234bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 124d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 125bb315f74SAnatolij Gustschin 126bb315f74SAnatolij Gustschin return in_be16(prv->regs + reg); 127bb315f74SAnatolij Gustschin } 128bb315f74SAnatolij Gustschin 129bb315f74SAnatolij Gustschin /* Write NFC register */ 130bb315f74SAnatolij Gustschin static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val) 131bb315f74SAnatolij Gustschin { 1324bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 133d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 134bb315f74SAnatolij Gustschin 135bb315f74SAnatolij Gustschin out_be16(prv->regs + reg, val); 136bb315f74SAnatolij Gustschin } 137bb315f74SAnatolij Gustschin 138bb315f74SAnatolij Gustschin /* Set bits in NFC register */ 139bb315f74SAnatolij Gustschin static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits) 140bb315f74SAnatolij Gustschin { 141bb315f74SAnatolij Gustschin nfc_write(mtd, reg, nfc_read(mtd, reg) | bits); 142bb315f74SAnatolij Gustschin } 143bb315f74SAnatolij Gustschin 144bb315f74SAnatolij Gustschin /* Clear bits in NFC register */ 145bb315f74SAnatolij Gustschin static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits) 146bb315f74SAnatolij Gustschin { 147bb315f74SAnatolij Gustschin nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits); 148bb315f74SAnatolij Gustschin } 149bb315f74SAnatolij Gustschin 150bb315f74SAnatolij Gustschin /* Invoke address cycle */ 151bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr) 152bb315f74SAnatolij Gustschin { 153bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_FLASH_ADDR, addr); 154bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS); 155bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 156bb315f74SAnatolij Gustschin } 157bb315f74SAnatolij Gustschin 158bb315f74SAnatolij Gustschin /* Invoke command cycle */ 159bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd) 160bb315f74SAnatolij Gustschin { 161bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_FLASH_CMD, cmd); 162bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND); 163bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 164bb315f74SAnatolij Gustschin } 165bb315f74SAnatolij Gustschin 166bb315f74SAnatolij Gustschin /* Send data from NFC buffers to NAND flash */ 167bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd) 168bb315f74SAnatolij Gustschin { 169bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 170bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_INPUT); 171bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 172bb315f74SAnatolij Gustschin } 173bb315f74SAnatolij Gustschin 174bb315f74SAnatolij Gustschin /* Receive data from NAND flash */ 175bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd) 176bb315f74SAnatolij Gustschin { 177bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 178bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT); 179bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 180bb315f74SAnatolij Gustschin } 181bb315f74SAnatolij Gustschin 182bb315f74SAnatolij Gustschin /* Receive ID from NAND flash */ 183bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd) 184bb315f74SAnatolij Gustschin { 185bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 186bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_ID); 187bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 188bb315f74SAnatolij Gustschin } 189bb315f74SAnatolij Gustschin 190bb315f74SAnatolij Gustschin /* Receive status from NAND flash */ 191bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd) 192bb315f74SAnatolij Gustschin { 193bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 194bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_STATUS); 195bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 196bb315f74SAnatolij Gustschin } 197bb315f74SAnatolij Gustschin 198bb315f74SAnatolij Gustschin /* NFC interrupt handler */ 199bb315f74SAnatolij Gustschin static irqreturn_t mpc5121_nfc_irq(int irq, void *data) 200bb315f74SAnatolij Gustschin { 201bb315f74SAnatolij Gustschin struct mtd_info *mtd = data; 2024bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 203d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 204bb315f74SAnatolij Gustschin 205bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK); 206bb315f74SAnatolij Gustschin wake_up(&prv->irq_waitq); 207bb315f74SAnatolij Gustschin 208bb315f74SAnatolij Gustschin return IRQ_HANDLED; 209bb315f74SAnatolij Gustschin } 210bb315f74SAnatolij Gustschin 211bb315f74SAnatolij Gustschin /* Wait for operation complete */ 212bb315f74SAnatolij Gustschin static void mpc5121_nfc_done(struct mtd_info *mtd) 213bb315f74SAnatolij Gustschin { 2144bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 215d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 216bb315f74SAnatolij Gustschin int rv; 217bb315f74SAnatolij Gustschin 218bb315f74SAnatolij Gustschin if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) { 219bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK); 220bb315f74SAnatolij Gustschin rv = wait_event_timeout(prv->irq_waitq, 221bb315f74SAnatolij Gustschin (nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT); 222bb315f74SAnatolij Gustschin 223bb315f74SAnatolij Gustschin if (!rv) 224bb315f74SAnatolij Gustschin dev_warn(prv->dev, 225bb315f74SAnatolij Gustschin "Timeout while waiting for interrupt.\n"); 226bb315f74SAnatolij Gustschin } 227bb315f74SAnatolij Gustschin 228bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_CONFIG2, NFC_INT); 229bb315f74SAnatolij Gustschin } 230bb315f74SAnatolij Gustschin 231bb315f74SAnatolij Gustschin /* Do address cycle(s) */ 232bb315f74SAnatolij Gustschin static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) 233bb315f74SAnatolij Gustschin { 2344bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 235bb315f74SAnatolij Gustschin u32 pagemask = chip->pagemask; 236bb315f74SAnatolij Gustschin 237bb315f74SAnatolij Gustschin if (column != -1) { 238bb315f74SAnatolij Gustschin mpc5121_nfc_send_addr(mtd, column); 239bb315f74SAnatolij Gustschin if (mtd->writesize > 512) 240bb315f74SAnatolij Gustschin mpc5121_nfc_send_addr(mtd, column >> 8); 241bb315f74SAnatolij Gustschin } 242bb315f74SAnatolij Gustschin 243bb315f74SAnatolij Gustschin if (page != -1) { 244bb315f74SAnatolij Gustschin do { 245bb315f74SAnatolij Gustschin mpc5121_nfc_send_addr(mtd, page & 0xFF); 246bb315f74SAnatolij Gustschin page >>= 8; 247bb315f74SAnatolij Gustschin pagemask >>= 8; 248bb315f74SAnatolij Gustschin } while (pagemask); 249bb315f74SAnatolij Gustschin } 250bb315f74SAnatolij Gustschin } 251bb315f74SAnatolij Gustschin 252bb315f74SAnatolij Gustschin /* Control chip select signals */ 253758b56f5SBoris Brezillon static void mpc5121_nfc_select_chip(struct nand_chip *nand, int chip) 254bb315f74SAnatolij Gustschin { 255758b56f5SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(nand); 256758b56f5SBoris Brezillon 257bb315f74SAnatolij Gustschin if (chip < 0) { 258bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_CONFIG1, NFC_CE); 259bb315f74SAnatolij Gustschin return; 260bb315f74SAnatolij Gustschin } 261bb315f74SAnatolij Gustschin 262bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK); 263bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) & 264bb315f74SAnatolij Gustschin NFC_ACTIVE_CS_MASK); 265bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_CE); 266bb315f74SAnatolij Gustschin } 267bb315f74SAnatolij Gustschin 268bb315f74SAnatolij Gustschin /* Init external chip select logic on ADS5121 board */ 269bb315f74SAnatolij Gustschin static int ads5121_chipselect_init(struct mtd_info *mtd) 270bb315f74SAnatolij Gustschin { 2714bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 272d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 273bb315f74SAnatolij Gustschin struct device_node *dn; 274bb315f74SAnatolij Gustschin 275bb315f74SAnatolij Gustschin dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld"); 276bb315f74SAnatolij Gustschin if (dn) { 277bb315f74SAnatolij Gustschin prv->csreg = of_iomap(dn, 0); 278bb315f74SAnatolij Gustschin of_node_put(dn); 279bb315f74SAnatolij Gustschin if (!prv->csreg) 280bb315f74SAnatolij Gustschin return -ENOMEM; 281bb315f74SAnatolij Gustschin 282bb315f74SAnatolij Gustschin /* CPLD Register 9 controls NAND /CE Lines */ 283bb315f74SAnatolij Gustschin prv->csreg += 9; 284bb315f74SAnatolij Gustschin return 0; 285bb315f74SAnatolij Gustschin } 286bb315f74SAnatolij Gustschin 287bb315f74SAnatolij Gustschin return -EINVAL; 288bb315f74SAnatolij Gustschin } 289bb315f74SAnatolij Gustschin 290bb315f74SAnatolij Gustschin /* Control chips select signal on ADS5121 board */ 291758b56f5SBoris Brezillon static void ads5121_select_chip(struct nand_chip *nand, int chip) 292bb315f74SAnatolij Gustschin { 293758b56f5SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(nand); 294d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand); 295bb315f74SAnatolij Gustschin u8 v; 296bb315f74SAnatolij Gustschin 297bb315f74SAnatolij Gustschin v = in_8(prv->csreg); 298bb315f74SAnatolij Gustschin v |= 0x0F; 299bb315f74SAnatolij Gustschin 300bb315f74SAnatolij Gustschin if (chip >= 0) { 301758b56f5SBoris Brezillon mpc5121_nfc_select_chip(nand, 0); 302bb315f74SAnatolij Gustschin v &= ~(1 << chip); 303bb315f74SAnatolij Gustschin } else 304758b56f5SBoris Brezillon mpc5121_nfc_select_chip(nand, -1); 305bb315f74SAnatolij Gustschin 306bb315f74SAnatolij Gustschin out_8(prv->csreg, v); 307bb315f74SAnatolij Gustschin } 308bb315f74SAnatolij Gustschin 309bb315f74SAnatolij Gustschin /* Read NAND Ready/Busy signal */ 31050a487e7SBoris Brezillon static int mpc5121_nfc_dev_ready(struct nand_chip *nand) 311bb315f74SAnatolij Gustschin { 312bb315f74SAnatolij Gustschin /* 313bb315f74SAnatolij Gustschin * NFC handles ready/busy signal internally. Therefore, this function 314bb315f74SAnatolij Gustschin * always returns status as ready. 315bb315f74SAnatolij Gustschin */ 316bb315f74SAnatolij Gustschin return 1; 317bb315f74SAnatolij Gustschin } 318bb315f74SAnatolij Gustschin 319bb315f74SAnatolij Gustschin /* Write command to NAND flash */ 3205295cf2eSBoris Brezillon static void mpc5121_nfc_command(struct nand_chip *chip, unsigned command, 321bb315f74SAnatolij Gustschin int column, int page) 322bb315f74SAnatolij Gustschin { 3235295cf2eSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 324d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 325bb315f74SAnatolij Gustschin 326bb315f74SAnatolij Gustschin prv->column = (column >= 0) ? column : 0; 327bb315f74SAnatolij Gustschin prv->spareonly = 0; 328bb315f74SAnatolij Gustschin 329bb315f74SAnatolij Gustschin switch (command) { 330bb315f74SAnatolij Gustschin case NAND_CMD_PAGEPROG: 331bb315f74SAnatolij Gustschin mpc5121_nfc_send_prog_page(mtd); 332bb315f74SAnatolij Gustschin break; 333bb315f74SAnatolij Gustschin /* 334bb315f74SAnatolij Gustschin * NFC does not support sub-page reads and writes, 335bb315f74SAnatolij Gustschin * so emulate them using full page transfers. 336bb315f74SAnatolij Gustschin */ 337bb315f74SAnatolij Gustschin case NAND_CMD_READ0: 338bb315f74SAnatolij Gustschin column = 0; 339bb315f74SAnatolij Gustschin break; 340bb315f74SAnatolij Gustschin 341bb315f74SAnatolij Gustschin case NAND_CMD_READ1: 342bb315f74SAnatolij Gustschin prv->column += 256; 343bb315f74SAnatolij Gustschin command = NAND_CMD_READ0; 344bb315f74SAnatolij Gustschin column = 0; 345bb315f74SAnatolij Gustschin break; 346bb315f74SAnatolij Gustschin 347bb315f74SAnatolij Gustschin case NAND_CMD_READOOB: 348bb315f74SAnatolij Gustschin prv->spareonly = 1; 349bb315f74SAnatolij Gustschin command = NAND_CMD_READ0; 350bb315f74SAnatolij Gustschin column = 0; 351bb315f74SAnatolij Gustschin break; 352bb315f74SAnatolij Gustschin 353bb315f74SAnatolij Gustschin case NAND_CMD_SEQIN: 3545295cf2eSBoris Brezillon mpc5121_nfc_command(chip, NAND_CMD_READ0, column, page); 355bb315f74SAnatolij Gustschin column = 0; 356bb315f74SAnatolij Gustschin break; 357bb315f74SAnatolij Gustschin 358bb315f74SAnatolij Gustschin case NAND_CMD_ERASE1: 359bb315f74SAnatolij Gustschin case NAND_CMD_ERASE2: 360bb315f74SAnatolij Gustschin case NAND_CMD_READID: 361bb315f74SAnatolij Gustschin case NAND_CMD_STATUS: 362bb315f74SAnatolij Gustschin break; 363bb315f74SAnatolij Gustschin 364bb315f74SAnatolij Gustschin default: 365bb315f74SAnatolij Gustschin return; 366bb315f74SAnatolij Gustschin } 367bb315f74SAnatolij Gustschin 368bb315f74SAnatolij Gustschin mpc5121_nfc_send_cmd(mtd, command); 369bb315f74SAnatolij Gustschin mpc5121_nfc_addr_cycle(mtd, column, page); 370bb315f74SAnatolij Gustschin 371bb315f74SAnatolij Gustschin switch (command) { 372bb315f74SAnatolij Gustschin case NAND_CMD_READ0: 373bb315f74SAnatolij Gustschin if (mtd->writesize > 512) 374bb315f74SAnatolij Gustschin mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART); 375bb315f74SAnatolij Gustschin mpc5121_nfc_send_read_page(mtd); 376bb315f74SAnatolij Gustschin break; 377bb315f74SAnatolij Gustschin 378bb315f74SAnatolij Gustschin case NAND_CMD_READID: 379bb315f74SAnatolij Gustschin mpc5121_nfc_send_read_id(mtd); 380bb315f74SAnatolij Gustschin break; 381bb315f74SAnatolij Gustschin 382bb315f74SAnatolij Gustschin case NAND_CMD_STATUS: 383bb315f74SAnatolij Gustschin mpc5121_nfc_send_read_status(mtd); 384bb315f74SAnatolij Gustschin if (chip->options & NAND_BUSWIDTH_16) 385bb315f74SAnatolij Gustschin prv->column = 1; 386bb315f74SAnatolij Gustschin else 387bb315f74SAnatolij Gustschin prv->column = 0; 388bb315f74SAnatolij Gustschin break; 389bb315f74SAnatolij Gustschin } 390bb315f74SAnatolij Gustschin } 391bb315f74SAnatolij Gustschin 392bb315f74SAnatolij Gustschin /* Copy data from/to NFC spare buffers. */ 393bb315f74SAnatolij Gustschin static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset, 394bb315f74SAnatolij Gustschin u8 *buffer, uint size, int wr) 395bb315f74SAnatolij Gustschin { 3964bd4ebccSBoris BREZILLON struct nand_chip *nand = mtd_to_nand(mtd); 397d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand); 398bb315f74SAnatolij Gustschin uint o, s, sbsize, blksize; 399bb315f74SAnatolij Gustschin 400bb315f74SAnatolij Gustschin /* 401bb315f74SAnatolij Gustschin * NAND spare area is available through NFC spare buffers. 402bb315f74SAnatolij Gustschin * The NFC divides spare area into (page_size / 512) chunks. 403bb315f74SAnatolij Gustschin * Each chunk is placed into separate spare memory area, using 404bb315f74SAnatolij Gustschin * first (spare_size / num_of_chunks) bytes of the buffer. 405bb315f74SAnatolij Gustschin * 406bb315f74SAnatolij Gustschin * For NAND device in which the spare area is not divided fully 407bb315f74SAnatolij Gustschin * by the number of chunks, number of used bytes in each spare 408bb315f74SAnatolij Gustschin * buffer is rounded down to the nearest even number of bytes, 409bb315f74SAnatolij Gustschin * and all remaining bytes are added to the last used spare area. 410bb315f74SAnatolij Gustschin * 411bb315f74SAnatolij Gustschin * For more information read section 26.6.10 of MPC5121e 412bb315f74SAnatolij Gustschin * Microcontroller Reference Manual, Rev. 3. 413bb315f74SAnatolij Gustschin */ 414bb315f74SAnatolij Gustschin 415bb315f74SAnatolij Gustschin /* Calculate number of valid bytes in each spare buffer */ 416bb315f74SAnatolij Gustschin sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1; 417bb315f74SAnatolij Gustschin 418bb315f74SAnatolij Gustschin while (size) { 419bb315f74SAnatolij Gustschin /* Calculate spare buffer number */ 420bb315f74SAnatolij Gustschin s = offset / sbsize; 421bb315f74SAnatolij Gustschin if (s > NFC_SPARE_BUFFERS - 1) 422bb315f74SAnatolij Gustschin s = NFC_SPARE_BUFFERS - 1; 423bb315f74SAnatolij Gustschin 424bb315f74SAnatolij Gustschin /* 425bb315f74SAnatolij Gustschin * Calculate offset to requested data block in selected spare 426bb315f74SAnatolij Gustschin * buffer and its size. 427bb315f74SAnatolij Gustschin */ 428bb315f74SAnatolij Gustschin o = offset - (s * sbsize); 429bb315f74SAnatolij Gustschin blksize = min(sbsize - o, size); 430bb315f74SAnatolij Gustschin 431bb315f74SAnatolij Gustschin if (wr) 432bb315f74SAnatolij Gustschin memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o, 433bb315f74SAnatolij Gustschin buffer, blksize); 434bb315f74SAnatolij Gustschin else 435bb315f74SAnatolij Gustschin memcpy_fromio(buffer, 436bb315f74SAnatolij Gustschin prv->regs + NFC_SPARE_AREA(s) + o, blksize); 437bb315f74SAnatolij Gustschin 438bb315f74SAnatolij Gustschin buffer += blksize; 439bb315f74SAnatolij Gustschin offset += blksize; 440bb315f74SAnatolij Gustschin size -= blksize; 441*73b265aeSzhengbin } 442bb315f74SAnatolij Gustschin } 443bb315f74SAnatolij Gustschin 444bb315f74SAnatolij Gustschin /* Copy data from/to NFC main and spare buffers */ 445bb315f74SAnatolij Gustschin static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len, 446bb315f74SAnatolij Gustschin int wr) 447bb315f74SAnatolij Gustschin { 4484bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 449d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 450bb315f74SAnatolij Gustschin uint c = prv->column; 451bb315f74SAnatolij Gustschin uint l; 452bb315f74SAnatolij Gustschin 453bb315f74SAnatolij Gustschin /* Handle spare area access */ 454bb315f74SAnatolij Gustschin if (prv->spareonly || c >= mtd->writesize) { 455bb315f74SAnatolij Gustschin /* Calculate offset from beginning of spare area */ 456bb315f74SAnatolij Gustschin if (c >= mtd->writesize) 457bb315f74SAnatolij Gustschin c -= mtd->writesize; 458bb315f74SAnatolij Gustschin 459bb315f74SAnatolij Gustschin prv->column += len; 460bb315f74SAnatolij Gustschin mpc5121_nfc_copy_spare(mtd, c, buf, len, wr); 461bb315f74SAnatolij Gustschin return; 462bb315f74SAnatolij Gustschin } 463bb315f74SAnatolij Gustschin 464bb315f74SAnatolij Gustschin /* 465bb315f74SAnatolij Gustschin * Handle main area access - limit copy length to prevent 466bb315f74SAnatolij Gustschin * crossing main/spare boundary. 467bb315f74SAnatolij Gustschin */ 468bb315f74SAnatolij Gustschin l = min((uint)len, mtd->writesize - c); 469bb315f74SAnatolij Gustschin prv->column += l; 470bb315f74SAnatolij Gustschin 471bb315f74SAnatolij Gustschin if (wr) 472bb315f74SAnatolij Gustschin memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l); 473bb315f74SAnatolij Gustschin else 474bb315f74SAnatolij Gustschin memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l); 475bb315f74SAnatolij Gustschin 476bb315f74SAnatolij Gustschin /* Handle crossing main/spare boundary */ 477bb315f74SAnatolij Gustschin if (l != len) { 478bb315f74SAnatolij Gustschin buf += l; 479bb315f74SAnatolij Gustschin len -= l; 480bb315f74SAnatolij Gustschin mpc5121_nfc_buf_copy(mtd, buf, len, wr); 481bb315f74SAnatolij Gustschin } 482bb315f74SAnatolij Gustschin } 483bb315f74SAnatolij Gustschin 484bb315f74SAnatolij Gustschin /* Read data from NFC buffers */ 4857e534323SBoris Brezillon static void mpc5121_nfc_read_buf(struct nand_chip *chip, u_char *buf, int len) 486bb315f74SAnatolij Gustschin { 4877e534323SBoris Brezillon mpc5121_nfc_buf_copy(nand_to_mtd(chip), buf, len, 0); 488bb315f74SAnatolij Gustschin } 489bb315f74SAnatolij Gustschin 490bb315f74SAnatolij Gustschin /* Write data to NFC buffers */ 491c0739d85SBoris Brezillon static void mpc5121_nfc_write_buf(struct nand_chip *chip, const u_char *buf, 492c0739d85SBoris Brezillon int len) 493bb315f74SAnatolij Gustschin { 494c0739d85SBoris Brezillon mpc5121_nfc_buf_copy(nand_to_mtd(chip), (u_char *)buf, len, 1); 495bb315f74SAnatolij Gustschin } 496bb315f74SAnatolij Gustschin 497bb315f74SAnatolij Gustschin /* Read byte from NFC buffers */ 4987e534323SBoris Brezillon static u8 mpc5121_nfc_read_byte(struct nand_chip *chip) 499bb315f74SAnatolij Gustschin { 500bb315f74SAnatolij Gustschin u8 tmp; 501bb315f74SAnatolij Gustschin 5027e534323SBoris Brezillon mpc5121_nfc_read_buf(chip, &tmp, sizeof(tmp)); 503bb315f74SAnatolij Gustschin 504bb315f74SAnatolij Gustschin return tmp; 505bb315f74SAnatolij Gustschin } 506bb315f74SAnatolij Gustschin 507bb315f74SAnatolij Gustschin /* 508bb315f74SAnatolij Gustschin * Read NFC configuration from Reset Config Word 509bb315f74SAnatolij Gustschin * 510bb315f74SAnatolij Gustschin * NFC is configured during reset in basis of information stored 511bb315f74SAnatolij Gustschin * in Reset Config Word. There is no other way to set NAND block 512bb315f74SAnatolij Gustschin * size, spare size and bus width. 513bb315f74SAnatolij Gustschin */ 514bb315f74SAnatolij Gustschin static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) 515bb315f74SAnatolij Gustschin { 5164bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 517d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 518bb315f74SAnatolij Gustschin struct mpc512x_reset_module *rm; 519bb315f74SAnatolij Gustschin struct device_node *rmnode; 520bb315f74SAnatolij Gustschin uint rcw_pagesize = 0; 521bb315f74SAnatolij Gustschin uint rcw_sparesize = 0; 522bb315f74SAnatolij Gustschin uint rcw_width; 523bb315f74SAnatolij Gustschin uint rcwh; 524bb315f74SAnatolij Gustschin uint romloc, ps; 525cf363518SJulia Lawall int ret = 0; 526bb315f74SAnatolij Gustschin 527bb315f74SAnatolij Gustschin rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset"); 528bb315f74SAnatolij Gustschin if (!rmnode) { 529bb315f74SAnatolij Gustschin dev_err(prv->dev, "Missing 'fsl,mpc5121-reset' " 530bb315f74SAnatolij Gustschin "node in device tree!\n"); 531bb315f74SAnatolij Gustschin return -ENODEV; 532bb315f74SAnatolij Gustschin } 533bb315f74SAnatolij Gustschin 534bb315f74SAnatolij Gustschin rm = of_iomap(rmnode, 0); 535bb315f74SAnatolij Gustschin if (!rm) { 536bb315f74SAnatolij Gustschin dev_err(prv->dev, "Error mapping reset module node!\n"); 537cf363518SJulia Lawall ret = -EBUSY; 538cf363518SJulia Lawall goto out; 539bb315f74SAnatolij Gustschin } 540bb315f74SAnatolij Gustschin 541bb315f74SAnatolij Gustschin rcwh = in_be32(&rm->rcwhr); 542bb315f74SAnatolij Gustschin 543bb315f74SAnatolij Gustschin /* Bit 6: NFC bus width */ 544bb315f74SAnatolij Gustschin rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1; 545bb315f74SAnatolij Gustschin 546bb315f74SAnatolij Gustschin /* Bit 7: NFC Page/Spare size */ 547bb315f74SAnatolij Gustschin ps = (rcwh >> 7) & 0x1; 548bb315f74SAnatolij Gustschin 549bb315f74SAnatolij Gustschin /* Bits [22:21]: ROM Location */ 550bb315f74SAnatolij Gustschin romloc = (rcwh >> 21) & 0x3; 551bb315f74SAnatolij Gustschin 552bb315f74SAnatolij Gustschin /* Decode RCW bits */ 553bb315f74SAnatolij Gustschin switch ((ps << 2) | romloc) { 554bb315f74SAnatolij Gustschin case 0x00: 555bb315f74SAnatolij Gustschin case 0x01: 556bb315f74SAnatolij Gustschin rcw_pagesize = 512; 557bb315f74SAnatolij Gustschin rcw_sparesize = 16; 558bb315f74SAnatolij Gustschin break; 559bb315f74SAnatolij Gustschin case 0x02: 560bb315f74SAnatolij Gustschin case 0x03: 561bb315f74SAnatolij Gustschin rcw_pagesize = 4096; 562bb315f74SAnatolij Gustschin rcw_sparesize = 128; 563bb315f74SAnatolij Gustschin break; 564bb315f74SAnatolij Gustschin case 0x04: 565bb315f74SAnatolij Gustschin case 0x05: 566bb315f74SAnatolij Gustschin rcw_pagesize = 2048; 567bb315f74SAnatolij Gustschin rcw_sparesize = 64; 568bb315f74SAnatolij Gustschin break; 569bb315f74SAnatolij Gustschin case 0x06: 570bb315f74SAnatolij Gustschin case 0x07: 571bb315f74SAnatolij Gustschin rcw_pagesize = 4096; 572bb315f74SAnatolij Gustschin rcw_sparesize = 218; 573bb315f74SAnatolij Gustschin break; 574bb315f74SAnatolij Gustschin } 575bb315f74SAnatolij Gustschin 576bb315f74SAnatolij Gustschin mtd->writesize = rcw_pagesize; 577bb315f74SAnatolij Gustschin mtd->oobsize = rcw_sparesize; 578bb315f74SAnatolij Gustschin if (rcw_width == 2) 579bb315f74SAnatolij Gustschin chip->options |= NAND_BUSWIDTH_16; 580bb315f74SAnatolij Gustschin 581bb315f74SAnatolij Gustschin dev_notice(prv->dev, "Configured for " 582bb315f74SAnatolij Gustschin "%u-bit NAND, page size %u " 583bb315f74SAnatolij Gustschin "with %u spare.\n", 584bb315f74SAnatolij Gustschin rcw_width * 8, rcw_pagesize, 585bb315f74SAnatolij Gustschin rcw_sparesize); 586bb315f74SAnatolij Gustschin iounmap(rm); 587cf363518SJulia Lawall out: 588bb315f74SAnatolij Gustschin of_node_put(rmnode); 589cf363518SJulia Lawall return ret; 590bb315f74SAnatolij Gustschin } 591bb315f74SAnatolij Gustschin 592bb315f74SAnatolij Gustschin /* Free driver resources */ 593bb315f74SAnatolij Gustschin static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd) 594bb315f74SAnatolij Gustschin { 5954bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 596d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 597bb315f74SAnatolij Gustschin 598180890c7SGerhard Sittig if (prv->clk) 599180890c7SGerhard Sittig clk_disable_unprepare(prv->clk); 600bb315f74SAnatolij Gustschin 601bb315f74SAnatolij Gustschin if (prv->csreg) 602bb315f74SAnatolij Gustschin iounmap(prv->csreg); 603bb315f74SAnatolij Gustschin } 604bb315f74SAnatolij Gustschin 60506f25510SBill Pemberton static int mpc5121_nfc_probe(struct platform_device *op) 606bb315f74SAnatolij Gustschin { 60723819f2eSChristophe Jaillet struct device_node *dn = op->dev.of_node; 608180890c7SGerhard Sittig struct clk *clk; 609bb315f74SAnatolij Gustschin struct device *dev = &op->dev; 610bb315f74SAnatolij Gustschin struct mpc5121_nfc_prv *prv; 611bb315f74SAnatolij Gustschin struct resource res; 612bb315f74SAnatolij Gustschin struct mtd_info *mtd; 613bb315f74SAnatolij Gustschin struct nand_chip *chip; 614bb315f74SAnatolij Gustschin unsigned long regs_paddr, regs_size; 615766f271aSIan Munsie const __be32 *chips_no; 616bb315f74SAnatolij Gustschin int resettime = 0; 617bb315f74SAnatolij Gustschin int retval = 0; 618bb315f74SAnatolij Gustschin int rev, len; 619bb315f74SAnatolij Gustschin 620bb315f74SAnatolij Gustschin /* 621bb315f74SAnatolij Gustschin * Check SoC revision. This driver supports only NFC 6226f1f3d0aSSteve Deiters * in MPC5121 revision 2 and MPC5123 revision 3. 623bb315f74SAnatolij Gustschin */ 624bb315f74SAnatolij Gustschin rev = (mfspr(SPRN_SVR) >> 4) & 0xF; 6256f1f3d0aSSteve Deiters if ((rev != 2) && (rev != 3)) { 626bb315f74SAnatolij Gustschin dev_err(dev, "SoC revision %u is not supported!\n", rev); 627bb315f74SAnatolij Gustschin return -ENXIO; 628bb315f74SAnatolij Gustschin } 629bb315f74SAnatolij Gustschin 630bb315f74SAnatolij Gustschin prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL); 63161a623feSJingoo Han if (!prv) 632bb315f74SAnatolij Gustschin return -ENOMEM; 633bb315f74SAnatolij Gustschin 634bb315f74SAnatolij Gustschin chip = &prv->chip; 6355a9f23ffSBoris BREZILLON mtd = nand_to_mtd(chip); 636bb315f74SAnatolij Gustschin 6377829ab93SFrans Klaver mtd->dev.parent = dev; 638d699ed25SBoris BREZILLON nand_set_controller_data(chip, prv); 639a61ae81aSBrian Norris nand_set_flash_node(chip, dn); 640bb315f74SAnatolij Gustschin prv->dev = dev; 641bb315f74SAnatolij Gustschin 642bb315f74SAnatolij Gustschin /* Read NFC configuration from Reset Config Word */ 643bb315f74SAnatolij Gustschin retval = mpc5121_nfc_read_hw_config(mtd); 644bb315f74SAnatolij Gustschin if (retval) { 645bb315f74SAnatolij Gustschin dev_err(dev, "Unable to read NFC config!\n"); 646bb315f74SAnatolij Gustschin return retval; 647bb315f74SAnatolij Gustschin } 648bb315f74SAnatolij Gustschin 649bb315f74SAnatolij Gustschin prv->irq = irq_of_parse_and_map(dn, 0); 650bb315f74SAnatolij Gustschin if (prv->irq == NO_IRQ) { 651bb315f74SAnatolij Gustschin dev_err(dev, "Error mapping IRQ!\n"); 652bb315f74SAnatolij Gustschin return -EINVAL; 653bb315f74SAnatolij Gustschin } 654bb315f74SAnatolij Gustschin 655bb315f74SAnatolij Gustschin retval = of_address_to_resource(dn, 0, &res); 656bb315f74SAnatolij Gustschin if (retval) { 657bb315f74SAnatolij Gustschin dev_err(dev, "Error parsing memory region!\n"); 658bb315f74SAnatolij Gustschin return retval; 659bb315f74SAnatolij Gustschin } 660bb315f74SAnatolij Gustschin 661bb315f74SAnatolij Gustschin chips_no = of_get_property(dn, "chips", &len); 662bb315f74SAnatolij Gustschin if (!chips_no || len != sizeof(*chips_no)) { 663bb315f74SAnatolij Gustschin dev_err(dev, "Invalid/missing 'chips' property!\n"); 664bb315f74SAnatolij Gustschin return -EINVAL; 665bb315f74SAnatolij Gustschin } 666bb315f74SAnatolij Gustschin 667bb315f74SAnatolij Gustschin regs_paddr = res.start; 66828f65c11SJoe Perches regs_size = resource_size(&res); 669bb315f74SAnatolij Gustschin 670bb315f74SAnatolij Gustschin if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) { 671bb315f74SAnatolij Gustschin dev_err(dev, "Error requesting memory region!\n"); 672bb315f74SAnatolij Gustschin return -EBUSY; 673bb315f74SAnatolij Gustschin } 674bb315f74SAnatolij Gustschin 675bb315f74SAnatolij Gustschin prv->regs = devm_ioremap(dev, regs_paddr, regs_size); 676bb315f74SAnatolij Gustschin if (!prv->regs) { 677bb315f74SAnatolij Gustschin dev_err(dev, "Error mapping memory region!\n"); 678bb315f74SAnatolij Gustschin return -ENOMEM; 679bb315f74SAnatolij Gustschin } 680bb315f74SAnatolij Gustschin 681bb315f74SAnatolij Gustschin mtd->name = "MPC5121 NAND"; 6828395b753SBoris Brezillon chip->legacy.dev_ready = mpc5121_nfc_dev_ready; 683bf6065c6SBoris Brezillon chip->legacy.cmdfunc = mpc5121_nfc_command; 684716bbbabSBoris Brezillon chip->legacy.read_byte = mpc5121_nfc_read_byte; 685716bbbabSBoris Brezillon chip->legacy.read_buf = mpc5121_nfc_read_buf; 686716bbbabSBoris Brezillon chip->legacy.write_buf = mpc5121_nfc_write_buf; 6877d6c37e9SBoris Brezillon chip->legacy.select_chip = mpc5121_nfc_select_chip; 68845240367SBoris Brezillon chip->legacy.set_features = nand_get_set_features_notsupp; 68945240367SBoris Brezillon chip->legacy.get_features = nand_get_set_features_notsupp; 690bb9ebd4eSBrian Norris chip->bbt_options = NAND_BBT_USE_FLASH; 691bb315f74SAnatolij Gustschin chip->ecc.mode = NAND_ECC_SOFT; 6927079e7edSRafał Miłecki chip->ecc.algo = NAND_ECC_HAMMING; 693bb315f74SAnatolij Gustschin 694bb315f74SAnatolij Gustschin /* Support external chip-select logic on ADS5121 board */ 69523819f2eSChristophe Jaillet if (of_machine_is_compatible("fsl,mpc5121ads")) { 696bb315f74SAnatolij Gustschin retval = ads5121_chipselect_init(mtd); 697bb315f74SAnatolij Gustschin if (retval) { 698bb315f74SAnatolij Gustschin dev_err(dev, "Chipselect init error!\n"); 699bb315f74SAnatolij Gustschin return retval; 700bb315f74SAnatolij Gustschin } 701bb315f74SAnatolij Gustschin 7027d6c37e9SBoris Brezillon chip->legacy.select_chip = ads5121_select_chip; 703bb315f74SAnatolij Gustschin } 704bb315f74SAnatolij Gustschin 705bb315f74SAnatolij Gustschin /* Enable NFC clock */ 70610de271fSGerhard Sittig clk = devm_clk_get(dev, "ipg"); 707180890c7SGerhard Sittig if (IS_ERR(clk)) { 708bb315f74SAnatolij Gustschin dev_err(dev, "Unable to acquire NFC clock!\n"); 709180890c7SGerhard Sittig retval = PTR_ERR(clk); 710bb315f74SAnatolij Gustschin goto error; 711bb315f74SAnatolij Gustschin } 712180890c7SGerhard Sittig retval = clk_prepare_enable(clk); 713180890c7SGerhard Sittig if (retval) { 714180890c7SGerhard Sittig dev_err(dev, "Unable to enable NFC clock!\n"); 715180890c7SGerhard Sittig goto error; 716180890c7SGerhard Sittig } 717180890c7SGerhard Sittig prv->clk = clk; 718bb315f74SAnatolij Gustschin 719bb315f74SAnatolij Gustschin /* Reset NAND Flash controller */ 720bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_RESET); 721bb315f74SAnatolij Gustschin while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) { 722bb315f74SAnatolij Gustschin if (resettime++ >= NFC_RESET_TIMEOUT) { 723bb315f74SAnatolij Gustschin dev_err(dev, "Timeout while resetting NFC!\n"); 724bb315f74SAnatolij Gustschin retval = -EINVAL; 725bb315f74SAnatolij Gustschin goto error; 726bb315f74SAnatolij Gustschin } 727bb315f74SAnatolij Gustschin 728bb315f74SAnatolij Gustschin udelay(1); 729bb315f74SAnatolij Gustschin } 730bb315f74SAnatolij Gustschin 731bb315f74SAnatolij Gustschin /* Enable write to NFC memory */ 732bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED); 733bb315f74SAnatolij Gustschin 734bb315f74SAnatolij Gustschin /* Enable write to all NAND pages */ 735bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000); 736bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF); 737bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK); 738bb315f74SAnatolij Gustschin 739bb315f74SAnatolij Gustschin /* 740bb315f74SAnatolij Gustschin * Setup NFC: 741bb315f74SAnatolij Gustschin * - Big Endian transfers, 742bb315f74SAnatolij Gustschin * - Interrupt after full page read/write. 743bb315f74SAnatolij Gustschin */ 744bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK | 745bb315f74SAnatolij Gustschin NFC_FULL_PAGE_INT); 746bb315f74SAnatolij Gustschin 747bb315f74SAnatolij Gustschin /* Set spare area size */ 748bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1); 749bb315f74SAnatolij Gustschin 750bb315f74SAnatolij Gustschin init_waitqueue_head(&prv->irq_waitq); 751bb315f74SAnatolij Gustschin retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME, 752bb315f74SAnatolij Gustschin mtd); 753bb315f74SAnatolij Gustschin if (retval) { 754bb315f74SAnatolij Gustschin dev_err(dev, "Error requesting IRQ!\n"); 755bb315f74SAnatolij Gustschin goto error; 756bb315f74SAnatolij Gustschin } 757bb315f74SAnatolij Gustschin 758bb315f74SAnatolij Gustschin /* Detect NAND chips */ 75900ad378fSBoris Brezillon retval = nand_scan(chip, be32_to_cpup(chips_no)); 760bbd4d03cSMasahiro Yamada if (retval) { 761bb315f74SAnatolij Gustschin dev_err(dev, "NAND Flash not found !\n"); 762bb315f74SAnatolij Gustschin goto error; 763bb315f74SAnatolij Gustschin } 764bb315f74SAnatolij Gustschin 765bb315f74SAnatolij Gustschin /* Set erase block size */ 766bb315f74SAnatolij Gustschin switch (mtd->erasesize / mtd->writesize) { 767bb315f74SAnatolij Gustschin case 32: 768bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32); 769bb315f74SAnatolij Gustschin break; 770bb315f74SAnatolij Gustschin 771bb315f74SAnatolij Gustschin case 64: 772bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64); 773bb315f74SAnatolij Gustschin break; 774bb315f74SAnatolij Gustschin 775bb315f74SAnatolij Gustschin case 128: 776bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128); 777bb315f74SAnatolij Gustschin break; 778bb315f74SAnatolij Gustschin 779bb315f74SAnatolij Gustschin case 256: 780bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256); 781bb315f74SAnatolij Gustschin break; 782bb315f74SAnatolij Gustschin 783bb315f74SAnatolij Gustschin default: 784bb315f74SAnatolij Gustschin dev_err(dev, "Unsupported NAND flash!\n"); 785bb315f74SAnatolij Gustschin retval = -ENXIO; 786bb315f74SAnatolij Gustschin goto error; 787bb315f74SAnatolij Gustschin } 788bb315f74SAnatolij Gustschin 789bb315f74SAnatolij Gustschin dev_set_drvdata(dev, mtd); 790bb315f74SAnatolij Gustschin 791bb315f74SAnatolij Gustschin /* Register device in MTD */ 792a61ae81aSBrian Norris retval = mtd_device_register(mtd, NULL, 0); 793bb315f74SAnatolij Gustschin if (retval) { 794bb315f74SAnatolij Gustschin dev_err(dev, "Error adding MTD device!\n"); 795bb315f74SAnatolij Gustschin goto error; 796bb315f74SAnatolij Gustschin } 797bb315f74SAnatolij Gustschin 798bb315f74SAnatolij Gustschin return 0; 799bb315f74SAnatolij Gustschin error: 800bb315f74SAnatolij Gustschin mpc5121_nfc_free(dev, mtd); 801bb315f74SAnatolij Gustschin return retval; 802bb315f74SAnatolij Gustschin } 803bb315f74SAnatolij Gustschin 804810b7e06SBill Pemberton static int mpc5121_nfc_remove(struct platform_device *op) 805bb315f74SAnatolij Gustschin { 806bb315f74SAnatolij Gustschin struct device *dev = &op->dev; 807bb315f74SAnatolij Gustschin struct mtd_info *mtd = dev_get_drvdata(dev); 808bb315f74SAnatolij Gustschin 80959ac276fSBoris Brezillon nand_release(mtd_to_nand(mtd)); 810bb315f74SAnatolij Gustschin mpc5121_nfc_free(dev, mtd); 811bb315f74SAnatolij Gustschin 812bb315f74SAnatolij Gustschin return 0; 813bb315f74SAnatolij Gustschin } 814bb315f74SAnatolij Gustschin 81566610443SFabian Frederick static const struct of_device_id mpc5121_nfc_match[] = { 816bb315f74SAnatolij Gustschin { .compatible = "fsl,mpc5121-nfc", }, 817bb315f74SAnatolij Gustschin {}, 818bb315f74SAnatolij Gustschin }; 8197446076eSLuis de Bethencourt MODULE_DEVICE_TABLE(of, mpc5121_nfc_match); 820bb315f74SAnatolij Gustschin 8211c48a5c9SGrant Likely static struct platform_driver mpc5121_nfc_driver = { 822bb315f74SAnatolij Gustschin .probe = mpc5121_nfc_probe, 8235153b88cSBill Pemberton .remove = mpc5121_nfc_remove, 824bb315f74SAnatolij Gustschin .driver = { 825bb315f74SAnatolij Gustschin .name = DRV_NAME, 82614acbbf8SAnatolij Gustschin .of_match_table = mpc5121_nfc_match, 827bb315f74SAnatolij Gustschin }, 828bb315f74SAnatolij Gustschin }; 829bb315f74SAnatolij Gustschin 830f99640deSAxel Lin module_platform_driver(mpc5121_nfc_driver); 831bb315f74SAnatolij Gustschin 832bb315f74SAnatolij Gustschin MODULE_AUTHOR("Freescale Semiconductor, Inc."); 833bb315f74SAnatolij Gustschin MODULE_DESCRIPTION("MPC5121 NAND MTD driver"); 834bb315f74SAnatolij Gustschin MODULE_LICENSE("GPL"); 835