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 { 1076dd09f77SMiquel Raynal struct nand_controller controller; 108bb315f74SAnatolij Gustschin struct nand_chip chip; 109bb315f74SAnatolij Gustschin int irq; 110bb315f74SAnatolij Gustschin void __iomem *regs; 111bb315f74SAnatolij Gustschin struct clk *clk; 112bb315f74SAnatolij Gustschin wait_queue_head_t irq_waitq; 113bb315f74SAnatolij Gustschin uint column; 114bb315f74SAnatolij Gustschin int spareonly; 115bb315f74SAnatolij Gustschin void __iomem *csreg; 116bb315f74SAnatolij Gustschin struct device *dev; 117bb315f74SAnatolij Gustschin }; 118bb315f74SAnatolij Gustschin 119bb315f74SAnatolij Gustschin static void mpc5121_nfc_done(struct mtd_info *mtd); 120bb315f74SAnatolij Gustschin 121bb315f74SAnatolij Gustschin /* Read NFC register */ 122bb315f74SAnatolij Gustschin static inline u16 nfc_read(struct mtd_info *mtd, uint reg) 123bb315f74SAnatolij Gustschin { 1244bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 125d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 126bb315f74SAnatolij Gustschin 127bb315f74SAnatolij Gustschin return in_be16(prv->regs + reg); 128bb315f74SAnatolij Gustschin } 129bb315f74SAnatolij Gustschin 130bb315f74SAnatolij Gustschin /* Write NFC register */ 131bb315f74SAnatolij Gustschin static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val) 132bb315f74SAnatolij Gustschin { 1334bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 134d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 135bb315f74SAnatolij Gustschin 136bb315f74SAnatolij Gustschin out_be16(prv->regs + reg, val); 137bb315f74SAnatolij Gustschin } 138bb315f74SAnatolij Gustschin 139bb315f74SAnatolij Gustschin /* Set bits in NFC register */ 140bb315f74SAnatolij Gustschin static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits) 141bb315f74SAnatolij Gustschin { 142bb315f74SAnatolij Gustschin nfc_write(mtd, reg, nfc_read(mtd, reg) | bits); 143bb315f74SAnatolij Gustschin } 144bb315f74SAnatolij Gustschin 145bb315f74SAnatolij Gustschin /* Clear bits in NFC register */ 146bb315f74SAnatolij Gustschin static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits) 147bb315f74SAnatolij Gustschin { 148bb315f74SAnatolij Gustschin nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits); 149bb315f74SAnatolij Gustschin } 150bb315f74SAnatolij Gustschin 151bb315f74SAnatolij Gustschin /* Invoke address cycle */ 152bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr) 153bb315f74SAnatolij Gustschin { 154bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_FLASH_ADDR, addr); 155bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS); 156bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 157bb315f74SAnatolij Gustschin } 158bb315f74SAnatolij Gustschin 159bb315f74SAnatolij Gustschin /* Invoke command cycle */ 160bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd) 161bb315f74SAnatolij Gustschin { 162bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_FLASH_CMD, cmd); 163bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND); 164bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 165bb315f74SAnatolij Gustschin } 166bb315f74SAnatolij Gustschin 167bb315f74SAnatolij Gustschin /* Send data from NFC buffers to NAND flash */ 168bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd) 169bb315f74SAnatolij Gustschin { 170bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 171bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_INPUT); 172bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 173bb315f74SAnatolij Gustschin } 174bb315f74SAnatolij Gustschin 175bb315f74SAnatolij Gustschin /* Receive data from NAND flash */ 176bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd) 177bb315f74SAnatolij Gustschin { 178bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 179bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT); 180bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 181bb315f74SAnatolij Gustschin } 182bb315f74SAnatolij Gustschin 183bb315f74SAnatolij Gustschin /* Receive ID from NAND flash */ 184bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd) 185bb315f74SAnatolij Gustschin { 186bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 187bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_ID); 188bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 189bb315f74SAnatolij Gustschin } 190bb315f74SAnatolij Gustschin 191bb315f74SAnatolij Gustschin /* Receive status from NAND flash */ 192bb315f74SAnatolij Gustschin static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd) 193bb315f74SAnatolij Gustschin { 194bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 195bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG2, NFC_STATUS); 196bb315f74SAnatolij Gustschin mpc5121_nfc_done(mtd); 197bb315f74SAnatolij Gustschin } 198bb315f74SAnatolij Gustschin 199bb315f74SAnatolij Gustschin /* NFC interrupt handler */ 200bb315f74SAnatolij Gustschin static irqreturn_t mpc5121_nfc_irq(int irq, void *data) 201bb315f74SAnatolij Gustschin { 202bb315f74SAnatolij Gustschin struct mtd_info *mtd = data; 2034bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 204d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 205bb315f74SAnatolij Gustschin 206bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK); 207bb315f74SAnatolij Gustschin wake_up(&prv->irq_waitq); 208bb315f74SAnatolij Gustschin 209bb315f74SAnatolij Gustschin return IRQ_HANDLED; 210bb315f74SAnatolij Gustschin } 211bb315f74SAnatolij Gustschin 212bb315f74SAnatolij Gustschin /* Wait for operation complete */ 213bb315f74SAnatolij Gustschin static void mpc5121_nfc_done(struct mtd_info *mtd) 214bb315f74SAnatolij Gustschin { 2154bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 216d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 217bb315f74SAnatolij Gustschin int rv; 218bb315f74SAnatolij Gustschin 219bb315f74SAnatolij Gustschin if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) { 220bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK); 221bb315f74SAnatolij Gustschin rv = wait_event_timeout(prv->irq_waitq, 222bb315f74SAnatolij Gustschin (nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT); 223bb315f74SAnatolij Gustschin 224bb315f74SAnatolij Gustschin if (!rv) 225bb315f74SAnatolij Gustschin dev_warn(prv->dev, 226bb315f74SAnatolij Gustschin "Timeout while waiting for interrupt.\n"); 227bb315f74SAnatolij Gustschin } 228bb315f74SAnatolij Gustschin 229bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_CONFIG2, NFC_INT); 230bb315f74SAnatolij Gustschin } 231bb315f74SAnatolij Gustschin 232bb315f74SAnatolij Gustschin /* Do address cycle(s) */ 233bb315f74SAnatolij Gustschin static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) 234bb315f74SAnatolij Gustschin { 2354bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 236bb315f74SAnatolij Gustschin u32 pagemask = chip->pagemask; 237bb315f74SAnatolij Gustschin 238bb315f74SAnatolij Gustschin if (column != -1) { 239bb315f74SAnatolij Gustschin mpc5121_nfc_send_addr(mtd, column); 240bb315f74SAnatolij Gustschin if (mtd->writesize > 512) 241bb315f74SAnatolij Gustschin mpc5121_nfc_send_addr(mtd, column >> 8); 242bb315f74SAnatolij Gustschin } 243bb315f74SAnatolij Gustschin 244bb315f74SAnatolij Gustschin if (page != -1) { 245bb315f74SAnatolij Gustschin do { 246bb315f74SAnatolij Gustschin mpc5121_nfc_send_addr(mtd, page & 0xFF); 247bb315f74SAnatolij Gustschin page >>= 8; 248bb315f74SAnatolij Gustschin pagemask >>= 8; 249bb315f74SAnatolij Gustschin } while (pagemask); 250bb315f74SAnatolij Gustschin } 251bb315f74SAnatolij Gustschin } 252bb315f74SAnatolij Gustschin 253bb315f74SAnatolij Gustschin /* Control chip select signals */ 254758b56f5SBoris Brezillon static void mpc5121_nfc_select_chip(struct nand_chip *nand, int chip) 255bb315f74SAnatolij Gustschin { 256758b56f5SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(nand); 257758b56f5SBoris Brezillon 258bb315f74SAnatolij Gustschin if (chip < 0) { 259bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_CONFIG1, NFC_CE); 260bb315f74SAnatolij Gustschin return; 261bb315f74SAnatolij Gustschin } 262bb315f74SAnatolij Gustschin 263bb315f74SAnatolij Gustschin nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK); 264bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) & 265bb315f74SAnatolij Gustschin NFC_ACTIVE_CS_MASK); 266bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_CE); 267bb315f74SAnatolij Gustschin } 268bb315f74SAnatolij Gustschin 269bb315f74SAnatolij Gustschin /* Init external chip select logic on ADS5121 board */ 270bb315f74SAnatolij Gustschin static int ads5121_chipselect_init(struct mtd_info *mtd) 271bb315f74SAnatolij Gustschin { 2724bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 273d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 274bb315f74SAnatolij Gustschin struct device_node *dn; 275bb315f74SAnatolij Gustschin 276bb315f74SAnatolij Gustschin dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld"); 277bb315f74SAnatolij Gustschin if (dn) { 278bb315f74SAnatolij Gustschin prv->csreg = of_iomap(dn, 0); 279bb315f74SAnatolij Gustschin of_node_put(dn); 280bb315f74SAnatolij Gustschin if (!prv->csreg) 281bb315f74SAnatolij Gustschin return -ENOMEM; 282bb315f74SAnatolij Gustschin 283bb315f74SAnatolij Gustschin /* CPLD Register 9 controls NAND /CE Lines */ 284bb315f74SAnatolij Gustschin prv->csreg += 9; 285bb315f74SAnatolij Gustschin return 0; 286bb315f74SAnatolij Gustschin } 287bb315f74SAnatolij Gustschin 288bb315f74SAnatolij Gustschin return -EINVAL; 289bb315f74SAnatolij Gustschin } 290bb315f74SAnatolij Gustschin 291bb315f74SAnatolij Gustschin /* Control chips select signal on ADS5121 board */ 292758b56f5SBoris Brezillon static void ads5121_select_chip(struct nand_chip *nand, int chip) 293bb315f74SAnatolij Gustschin { 294758b56f5SBoris Brezillon struct mtd_info *mtd = nand_to_mtd(nand); 295d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand); 296bb315f74SAnatolij Gustschin u8 v; 297bb315f74SAnatolij Gustschin 298bb315f74SAnatolij Gustschin v = in_8(prv->csreg); 299bb315f74SAnatolij Gustschin v |= 0x0F; 300bb315f74SAnatolij Gustschin 301bb315f74SAnatolij Gustschin if (chip >= 0) { 302758b56f5SBoris Brezillon mpc5121_nfc_select_chip(nand, 0); 303bb315f74SAnatolij Gustschin v &= ~(1 << chip); 304bb315f74SAnatolij Gustschin } else 305758b56f5SBoris Brezillon mpc5121_nfc_select_chip(nand, -1); 306bb315f74SAnatolij Gustschin 307bb315f74SAnatolij Gustschin out_8(prv->csreg, v); 308bb315f74SAnatolij Gustschin } 309bb315f74SAnatolij Gustschin 310bb315f74SAnatolij Gustschin /* Read NAND Ready/Busy signal */ 31150a487e7SBoris Brezillon static int mpc5121_nfc_dev_ready(struct nand_chip *nand) 312bb315f74SAnatolij Gustschin { 313bb315f74SAnatolij Gustschin /* 314bb315f74SAnatolij Gustschin * NFC handles ready/busy signal internally. Therefore, this function 315bb315f74SAnatolij Gustschin * always returns status as ready. 316bb315f74SAnatolij Gustschin */ 317bb315f74SAnatolij Gustschin return 1; 318bb315f74SAnatolij Gustschin } 319bb315f74SAnatolij Gustschin 320bb315f74SAnatolij Gustschin /* Write command to NAND flash */ 3215295cf2eSBoris Brezillon static void mpc5121_nfc_command(struct nand_chip *chip, unsigned command, 322bb315f74SAnatolij Gustschin int column, int page) 323bb315f74SAnatolij Gustschin { 3245295cf2eSBoris Brezillon struct mtd_info *mtd = nand_to_mtd(chip); 325d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 326bb315f74SAnatolij Gustschin 327bb315f74SAnatolij Gustschin prv->column = (column >= 0) ? column : 0; 328bb315f74SAnatolij Gustschin prv->spareonly = 0; 329bb315f74SAnatolij Gustschin 330bb315f74SAnatolij Gustschin switch (command) { 331bb315f74SAnatolij Gustschin case NAND_CMD_PAGEPROG: 332bb315f74SAnatolij Gustschin mpc5121_nfc_send_prog_page(mtd); 333bb315f74SAnatolij Gustschin break; 334bb315f74SAnatolij Gustschin /* 335bb315f74SAnatolij Gustschin * NFC does not support sub-page reads and writes, 336bb315f74SAnatolij Gustschin * so emulate them using full page transfers. 337bb315f74SAnatolij Gustschin */ 338bb315f74SAnatolij Gustschin case NAND_CMD_READ0: 339bb315f74SAnatolij Gustschin column = 0; 340bb315f74SAnatolij Gustschin break; 341bb315f74SAnatolij Gustschin 342bb315f74SAnatolij Gustschin case NAND_CMD_READ1: 343bb315f74SAnatolij Gustschin prv->column += 256; 344bb315f74SAnatolij Gustschin command = NAND_CMD_READ0; 345bb315f74SAnatolij Gustschin column = 0; 346bb315f74SAnatolij Gustschin break; 347bb315f74SAnatolij Gustschin 348bb315f74SAnatolij Gustschin case NAND_CMD_READOOB: 349bb315f74SAnatolij Gustschin prv->spareonly = 1; 350bb315f74SAnatolij Gustschin command = NAND_CMD_READ0; 351bb315f74SAnatolij Gustschin column = 0; 352bb315f74SAnatolij Gustschin break; 353bb315f74SAnatolij Gustschin 354bb315f74SAnatolij Gustschin case NAND_CMD_SEQIN: 3555295cf2eSBoris Brezillon mpc5121_nfc_command(chip, NAND_CMD_READ0, column, page); 356bb315f74SAnatolij Gustschin column = 0; 357bb315f74SAnatolij Gustschin break; 358bb315f74SAnatolij Gustschin 359bb315f74SAnatolij Gustschin case NAND_CMD_ERASE1: 360bb315f74SAnatolij Gustschin case NAND_CMD_ERASE2: 361bb315f74SAnatolij Gustschin case NAND_CMD_READID: 362bb315f74SAnatolij Gustschin case NAND_CMD_STATUS: 363bb315f74SAnatolij Gustschin break; 364bb315f74SAnatolij Gustschin 365bb315f74SAnatolij Gustschin default: 366bb315f74SAnatolij Gustschin return; 367bb315f74SAnatolij Gustschin } 368bb315f74SAnatolij Gustschin 369bb315f74SAnatolij Gustschin mpc5121_nfc_send_cmd(mtd, command); 370bb315f74SAnatolij Gustschin mpc5121_nfc_addr_cycle(mtd, column, page); 371bb315f74SAnatolij Gustschin 372bb315f74SAnatolij Gustschin switch (command) { 373bb315f74SAnatolij Gustschin case NAND_CMD_READ0: 374bb315f74SAnatolij Gustschin if (mtd->writesize > 512) 375bb315f74SAnatolij Gustschin mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART); 376bb315f74SAnatolij Gustschin mpc5121_nfc_send_read_page(mtd); 377bb315f74SAnatolij Gustschin break; 378bb315f74SAnatolij Gustschin 379bb315f74SAnatolij Gustschin case NAND_CMD_READID: 380bb315f74SAnatolij Gustschin mpc5121_nfc_send_read_id(mtd); 381bb315f74SAnatolij Gustschin break; 382bb315f74SAnatolij Gustschin 383bb315f74SAnatolij Gustschin case NAND_CMD_STATUS: 384bb315f74SAnatolij Gustschin mpc5121_nfc_send_read_status(mtd); 385bb315f74SAnatolij Gustschin if (chip->options & NAND_BUSWIDTH_16) 386bb315f74SAnatolij Gustschin prv->column = 1; 387bb315f74SAnatolij Gustschin else 388bb315f74SAnatolij Gustschin prv->column = 0; 389bb315f74SAnatolij Gustschin break; 390bb315f74SAnatolij Gustschin } 391bb315f74SAnatolij Gustschin } 392bb315f74SAnatolij Gustschin 393bb315f74SAnatolij Gustschin /* Copy data from/to NFC spare buffers. */ 394bb315f74SAnatolij Gustschin static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset, 395bb315f74SAnatolij Gustschin u8 *buffer, uint size, int wr) 396bb315f74SAnatolij Gustschin { 3974bd4ebccSBoris BREZILLON struct nand_chip *nand = mtd_to_nand(mtd); 398d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand); 399bb315f74SAnatolij Gustschin uint o, s, sbsize, blksize; 400bb315f74SAnatolij Gustschin 401bb315f74SAnatolij Gustschin /* 402bb315f74SAnatolij Gustschin * NAND spare area is available through NFC spare buffers. 403bb315f74SAnatolij Gustschin * The NFC divides spare area into (page_size / 512) chunks. 404bb315f74SAnatolij Gustschin * Each chunk is placed into separate spare memory area, using 405bb315f74SAnatolij Gustschin * first (spare_size / num_of_chunks) bytes of the buffer. 406bb315f74SAnatolij Gustschin * 407bb315f74SAnatolij Gustschin * For NAND device in which the spare area is not divided fully 408bb315f74SAnatolij Gustschin * by the number of chunks, number of used bytes in each spare 409bb315f74SAnatolij Gustschin * buffer is rounded down to the nearest even number of bytes, 410bb315f74SAnatolij Gustschin * and all remaining bytes are added to the last used spare area. 411bb315f74SAnatolij Gustschin * 412bb315f74SAnatolij Gustschin * For more information read section 26.6.10 of MPC5121e 413bb315f74SAnatolij Gustschin * Microcontroller Reference Manual, Rev. 3. 414bb315f74SAnatolij Gustschin */ 415bb315f74SAnatolij Gustschin 416bb315f74SAnatolij Gustschin /* Calculate number of valid bytes in each spare buffer */ 417bb315f74SAnatolij Gustschin sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1; 418bb315f74SAnatolij Gustschin 419bb315f74SAnatolij Gustschin while (size) { 420bb315f74SAnatolij Gustschin /* Calculate spare buffer number */ 421bb315f74SAnatolij Gustschin s = offset / sbsize; 422bb315f74SAnatolij Gustschin if (s > NFC_SPARE_BUFFERS - 1) 423bb315f74SAnatolij Gustschin s = NFC_SPARE_BUFFERS - 1; 424bb315f74SAnatolij Gustschin 425bb315f74SAnatolij Gustschin /* 426bb315f74SAnatolij Gustschin * Calculate offset to requested data block in selected spare 427bb315f74SAnatolij Gustschin * buffer and its size. 428bb315f74SAnatolij Gustschin */ 429bb315f74SAnatolij Gustschin o = offset - (s * sbsize); 430bb315f74SAnatolij Gustschin blksize = min(sbsize - o, size); 431bb315f74SAnatolij Gustschin 432bb315f74SAnatolij Gustschin if (wr) 433bb315f74SAnatolij Gustschin memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o, 434bb315f74SAnatolij Gustschin buffer, blksize); 435bb315f74SAnatolij Gustschin else 436bb315f74SAnatolij Gustschin memcpy_fromio(buffer, 437bb315f74SAnatolij Gustschin prv->regs + NFC_SPARE_AREA(s) + o, blksize); 438bb315f74SAnatolij Gustschin 439bb315f74SAnatolij Gustschin buffer += blksize; 440bb315f74SAnatolij Gustschin offset += blksize; 441bb315f74SAnatolij Gustschin size -= blksize; 44273b265aeSzhengbin } 443bb315f74SAnatolij Gustschin } 444bb315f74SAnatolij Gustschin 445bb315f74SAnatolij Gustschin /* Copy data from/to NFC main and spare buffers */ 446bb315f74SAnatolij Gustschin static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len, 447bb315f74SAnatolij Gustschin int wr) 448bb315f74SAnatolij Gustschin { 4494bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 450d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 451bb315f74SAnatolij Gustschin uint c = prv->column; 452bb315f74SAnatolij Gustschin uint l; 453bb315f74SAnatolij Gustschin 454bb315f74SAnatolij Gustschin /* Handle spare area access */ 455bb315f74SAnatolij Gustschin if (prv->spareonly || c >= mtd->writesize) { 456bb315f74SAnatolij Gustschin /* Calculate offset from beginning of spare area */ 457bb315f74SAnatolij Gustschin if (c >= mtd->writesize) 458bb315f74SAnatolij Gustschin c -= mtd->writesize; 459bb315f74SAnatolij Gustschin 460bb315f74SAnatolij Gustschin prv->column += len; 461bb315f74SAnatolij Gustschin mpc5121_nfc_copy_spare(mtd, c, buf, len, wr); 462bb315f74SAnatolij Gustschin return; 463bb315f74SAnatolij Gustschin } 464bb315f74SAnatolij Gustschin 465bb315f74SAnatolij Gustschin /* 466bb315f74SAnatolij Gustschin * Handle main area access - limit copy length to prevent 467bb315f74SAnatolij Gustschin * crossing main/spare boundary. 468bb315f74SAnatolij Gustschin */ 469bb315f74SAnatolij Gustschin l = min((uint)len, mtd->writesize - c); 470bb315f74SAnatolij Gustschin prv->column += l; 471bb315f74SAnatolij Gustschin 472bb315f74SAnatolij Gustschin if (wr) 473bb315f74SAnatolij Gustschin memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l); 474bb315f74SAnatolij Gustschin else 475bb315f74SAnatolij Gustschin memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l); 476bb315f74SAnatolij Gustschin 477bb315f74SAnatolij Gustschin /* Handle crossing main/spare boundary */ 478bb315f74SAnatolij Gustschin if (l != len) { 479bb315f74SAnatolij Gustschin buf += l; 480bb315f74SAnatolij Gustschin len -= l; 481bb315f74SAnatolij Gustschin mpc5121_nfc_buf_copy(mtd, buf, len, wr); 482bb315f74SAnatolij Gustschin } 483bb315f74SAnatolij Gustschin } 484bb315f74SAnatolij Gustschin 485bb315f74SAnatolij Gustschin /* Read data from NFC buffers */ 4867e534323SBoris Brezillon static void mpc5121_nfc_read_buf(struct nand_chip *chip, u_char *buf, int len) 487bb315f74SAnatolij Gustschin { 4887e534323SBoris Brezillon mpc5121_nfc_buf_copy(nand_to_mtd(chip), buf, len, 0); 489bb315f74SAnatolij Gustschin } 490bb315f74SAnatolij Gustschin 491bb315f74SAnatolij Gustschin /* Write data to NFC buffers */ 492c0739d85SBoris Brezillon static void mpc5121_nfc_write_buf(struct nand_chip *chip, const u_char *buf, 493c0739d85SBoris Brezillon int len) 494bb315f74SAnatolij Gustschin { 495c0739d85SBoris Brezillon mpc5121_nfc_buf_copy(nand_to_mtd(chip), (u_char *)buf, len, 1); 496bb315f74SAnatolij Gustschin } 497bb315f74SAnatolij Gustschin 498bb315f74SAnatolij Gustschin /* Read byte from NFC buffers */ 4997e534323SBoris Brezillon static u8 mpc5121_nfc_read_byte(struct nand_chip *chip) 500bb315f74SAnatolij Gustschin { 501bb315f74SAnatolij Gustschin u8 tmp; 502bb315f74SAnatolij Gustschin 5037e534323SBoris Brezillon mpc5121_nfc_read_buf(chip, &tmp, sizeof(tmp)); 504bb315f74SAnatolij Gustschin 505bb315f74SAnatolij Gustschin return tmp; 506bb315f74SAnatolij Gustschin } 507bb315f74SAnatolij Gustschin 508bb315f74SAnatolij Gustschin /* 509bb315f74SAnatolij Gustschin * Read NFC configuration from Reset Config Word 510bb315f74SAnatolij Gustschin * 511bb315f74SAnatolij Gustschin * NFC is configured during reset in basis of information stored 512bb315f74SAnatolij Gustschin * in Reset Config Word. There is no other way to set NAND block 513bb315f74SAnatolij Gustschin * size, spare size and bus width. 514bb315f74SAnatolij Gustschin */ 515bb315f74SAnatolij Gustschin static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) 516bb315f74SAnatolij Gustschin { 5174bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 518d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 519bb315f74SAnatolij Gustschin struct mpc512x_reset_module *rm; 520bb315f74SAnatolij Gustschin struct device_node *rmnode; 521bb315f74SAnatolij Gustschin uint rcw_pagesize = 0; 522bb315f74SAnatolij Gustschin uint rcw_sparesize = 0; 523bb315f74SAnatolij Gustschin uint rcw_width; 524bb315f74SAnatolij Gustschin uint rcwh; 525bb315f74SAnatolij Gustschin uint romloc, ps; 526cf363518SJulia Lawall int ret = 0; 527bb315f74SAnatolij Gustschin 528bb315f74SAnatolij Gustschin rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset"); 529bb315f74SAnatolij Gustschin if (!rmnode) { 530bb315f74SAnatolij Gustschin dev_err(prv->dev, "Missing 'fsl,mpc5121-reset' " 531bb315f74SAnatolij Gustschin "node in device tree!\n"); 532bb315f74SAnatolij Gustschin return -ENODEV; 533bb315f74SAnatolij Gustschin } 534bb315f74SAnatolij Gustschin 535bb315f74SAnatolij Gustschin rm = of_iomap(rmnode, 0); 536bb315f74SAnatolij Gustschin if (!rm) { 537bb315f74SAnatolij Gustschin dev_err(prv->dev, "Error mapping reset module node!\n"); 538cf363518SJulia Lawall ret = -EBUSY; 539cf363518SJulia Lawall goto out; 540bb315f74SAnatolij Gustschin } 541bb315f74SAnatolij Gustschin 542bb315f74SAnatolij Gustschin rcwh = in_be32(&rm->rcwhr); 543bb315f74SAnatolij Gustschin 544bb315f74SAnatolij Gustschin /* Bit 6: NFC bus width */ 545bb315f74SAnatolij Gustschin rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1; 546bb315f74SAnatolij Gustschin 547bb315f74SAnatolij Gustschin /* Bit 7: NFC Page/Spare size */ 548bb315f74SAnatolij Gustschin ps = (rcwh >> 7) & 0x1; 549bb315f74SAnatolij Gustschin 550bb315f74SAnatolij Gustschin /* Bits [22:21]: ROM Location */ 551bb315f74SAnatolij Gustschin romloc = (rcwh >> 21) & 0x3; 552bb315f74SAnatolij Gustschin 553bb315f74SAnatolij Gustschin /* Decode RCW bits */ 554bb315f74SAnatolij Gustschin switch ((ps << 2) | romloc) { 555bb315f74SAnatolij Gustschin case 0x00: 556bb315f74SAnatolij Gustschin case 0x01: 557bb315f74SAnatolij Gustschin rcw_pagesize = 512; 558bb315f74SAnatolij Gustschin rcw_sparesize = 16; 559bb315f74SAnatolij Gustschin break; 560bb315f74SAnatolij Gustschin case 0x02: 561bb315f74SAnatolij Gustschin case 0x03: 562bb315f74SAnatolij Gustschin rcw_pagesize = 4096; 563bb315f74SAnatolij Gustschin rcw_sparesize = 128; 564bb315f74SAnatolij Gustschin break; 565bb315f74SAnatolij Gustschin case 0x04: 566bb315f74SAnatolij Gustschin case 0x05: 567bb315f74SAnatolij Gustschin rcw_pagesize = 2048; 568bb315f74SAnatolij Gustschin rcw_sparesize = 64; 569bb315f74SAnatolij Gustschin break; 570bb315f74SAnatolij Gustschin case 0x06: 571bb315f74SAnatolij Gustschin case 0x07: 572bb315f74SAnatolij Gustschin rcw_pagesize = 4096; 573bb315f74SAnatolij Gustschin rcw_sparesize = 218; 574bb315f74SAnatolij Gustschin break; 575bb315f74SAnatolij Gustschin } 576bb315f74SAnatolij Gustschin 577bb315f74SAnatolij Gustschin mtd->writesize = rcw_pagesize; 578bb315f74SAnatolij Gustschin mtd->oobsize = rcw_sparesize; 579bb315f74SAnatolij Gustschin if (rcw_width == 2) 580bb315f74SAnatolij Gustschin chip->options |= NAND_BUSWIDTH_16; 581bb315f74SAnatolij Gustschin 582bb315f74SAnatolij Gustschin dev_notice(prv->dev, "Configured for " 583bb315f74SAnatolij Gustschin "%u-bit NAND, page size %u " 584bb315f74SAnatolij Gustschin "with %u spare.\n", 585bb315f74SAnatolij Gustschin rcw_width * 8, rcw_pagesize, 586bb315f74SAnatolij Gustschin rcw_sparesize); 587bb315f74SAnatolij Gustschin iounmap(rm); 588cf363518SJulia Lawall out: 589bb315f74SAnatolij Gustschin of_node_put(rmnode); 590cf363518SJulia Lawall return ret; 591bb315f74SAnatolij Gustschin } 592bb315f74SAnatolij Gustschin 593bb315f74SAnatolij Gustschin /* Free driver resources */ 594bb315f74SAnatolij Gustschin static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd) 595bb315f74SAnatolij Gustschin { 5964bd4ebccSBoris BREZILLON struct nand_chip *chip = mtd_to_nand(mtd); 597d699ed25SBoris BREZILLON struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 598bb315f74SAnatolij Gustschin 599180890c7SGerhard Sittig if (prv->clk) 600180890c7SGerhard Sittig clk_disable_unprepare(prv->clk); 601bb315f74SAnatolij Gustschin 602bb315f74SAnatolij Gustschin if (prv->csreg) 603bb315f74SAnatolij Gustschin iounmap(prv->csreg); 604bb315f74SAnatolij Gustschin } 605bb315f74SAnatolij Gustschin 6066dd09f77SMiquel Raynal static int mpc5121_nfc_attach_chip(struct nand_chip *chip) 6076dd09f77SMiquel Raynal { 6086dd09f77SMiquel Raynal chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; 609*f49bde9fSMiquel Raynal 610*f49bde9fSMiquel Raynal if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN) 6116dd09f77SMiquel Raynal chip->ecc.algo = NAND_ECC_ALGO_HAMMING; 6126dd09f77SMiquel Raynal 6136dd09f77SMiquel Raynal return 0; 6146dd09f77SMiquel Raynal } 6156dd09f77SMiquel Raynal 6166dd09f77SMiquel Raynal static const struct nand_controller_ops mpc5121_nfc_ops = { 6176dd09f77SMiquel Raynal .attach_chip = mpc5121_nfc_attach_chip, 6186dd09f77SMiquel Raynal }; 6196dd09f77SMiquel Raynal 62006f25510SBill Pemberton static int mpc5121_nfc_probe(struct platform_device *op) 621bb315f74SAnatolij Gustschin { 62223819f2eSChristophe Jaillet struct device_node *dn = op->dev.of_node; 623180890c7SGerhard Sittig struct clk *clk; 624bb315f74SAnatolij Gustschin struct device *dev = &op->dev; 625bb315f74SAnatolij Gustschin struct mpc5121_nfc_prv *prv; 626bb315f74SAnatolij Gustschin struct resource res; 627bb315f74SAnatolij Gustschin struct mtd_info *mtd; 628bb315f74SAnatolij Gustschin struct nand_chip *chip; 629bb315f74SAnatolij Gustschin unsigned long regs_paddr, regs_size; 630766f271aSIan Munsie const __be32 *chips_no; 631bb315f74SAnatolij Gustschin int resettime = 0; 632bb315f74SAnatolij Gustschin int retval = 0; 633bb315f74SAnatolij Gustschin int rev, len; 634bb315f74SAnatolij Gustschin 635bb315f74SAnatolij Gustschin /* 636bb315f74SAnatolij Gustschin * Check SoC revision. This driver supports only NFC 6376f1f3d0aSSteve Deiters * in MPC5121 revision 2 and MPC5123 revision 3. 638bb315f74SAnatolij Gustschin */ 639bb315f74SAnatolij Gustschin rev = (mfspr(SPRN_SVR) >> 4) & 0xF; 6406f1f3d0aSSteve Deiters if ((rev != 2) && (rev != 3)) { 641bb315f74SAnatolij Gustschin dev_err(dev, "SoC revision %u is not supported!\n", rev); 642bb315f74SAnatolij Gustschin return -ENXIO; 643bb315f74SAnatolij Gustschin } 644bb315f74SAnatolij Gustschin 645bb315f74SAnatolij Gustschin prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL); 64661a623feSJingoo Han if (!prv) 647bb315f74SAnatolij Gustschin return -ENOMEM; 648bb315f74SAnatolij Gustschin 649bb315f74SAnatolij Gustschin chip = &prv->chip; 6505a9f23ffSBoris BREZILLON mtd = nand_to_mtd(chip); 651bb315f74SAnatolij Gustschin 6526dd09f77SMiquel Raynal nand_controller_init(&prv->controller); 6536dd09f77SMiquel Raynal prv->controller.ops = &mpc5121_nfc_ops; 6546dd09f77SMiquel Raynal chip->controller = &prv->controller; 6556dd09f77SMiquel Raynal 6567829ab93SFrans Klaver mtd->dev.parent = dev; 657d699ed25SBoris BREZILLON nand_set_controller_data(chip, prv); 658a61ae81aSBrian Norris nand_set_flash_node(chip, dn); 659bb315f74SAnatolij Gustschin prv->dev = dev; 660bb315f74SAnatolij Gustschin 661bb315f74SAnatolij Gustschin /* Read NFC configuration from Reset Config Word */ 662bb315f74SAnatolij Gustschin retval = mpc5121_nfc_read_hw_config(mtd); 663bb315f74SAnatolij Gustschin if (retval) { 664bb315f74SAnatolij Gustschin dev_err(dev, "Unable to read NFC config!\n"); 665bb315f74SAnatolij Gustschin return retval; 666bb315f74SAnatolij Gustschin } 667bb315f74SAnatolij Gustschin 668bb315f74SAnatolij Gustschin prv->irq = irq_of_parse_and_map(dn, 0); 669bb315f74SAnatolij Gustschin if (prv->irq == NO_IRQ) { 670bb315f74SAnatolij Gustschin dev_err(dev, "Error mapping IRQ!\n"); 671bb315f74SAnatolij Gustschin return -EINVAL; 672bb315f74SAnatolij Gustschin } 673bb315f74SAnatolij Gustschin 674bb315f74SAnatolij Gustschin retval = of_address_to_resource(dn, 0, &res); 675bb315f74SAnatolij Gustschin if (retval) { 676bb315f74SAnatolij Gustschin dev_err(dev, "Error parsing memory region!\n"); 677bb315f74SAnatolij Gustschin return retval; 678bb315f74SAnatolij Gustschin } 679bb315f74SAnatolij Gustschin 680bb315f74SAnatolij Gustschin chips_no = of_get_property(dn, "chips", &len); 681bb315f74SAnatolij Gustschin if (!chips_no || len != sizeof(*chips_no)) { 682bb315f74SAnatolij Gustschin dev_err(dev, "Invalid/missing 'chips' property!\n"); 683bb315f74SAnatolij Gustschin return -EINVAL; 684bb315f74SAnatolij Gustschin } 685bb315f74SAnatolij Gustschin 686bb315f74SAnatolij Gustschin regs_paddr = res.start; 68728f65c11SJoe Perches regs_size = resource_size(&res); 688bb315f74SAnatolij Gustschin 689bb315f74SAnatolij Gustschin if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) { 690bb315f74SAnatolij Gustschin dev_err(dev, "Error requesting memory region!\n"); 691bb315f74SAnatolij Gustschin return -EBUSY; 692bb315f74SAnatolij Gustschin } 693bb315f74SAnatolij Gustschin 694bb315f74SAnatolij Gustschin prv->regs = devm_ioremap(dev, regs_paddr, regs_size); 695bb315f74SAnatolij Gustschin if (!prv->regs) { 696bb315f74SAnatolij Gustschin dev_err(dev, "Error mapping memory region!\n"); 697bb315f74SAnatolij Gustschin return -ENOMEM; 698bb315f74SAnatolij Gustschin } 699bb315f74SAnatolij Gustschin 700bb315f74SAnatolij Gustschin mtd->name = "MPC5121 NAND"; 7018395b753SBoris Brezillon chip->legacy.dev_ready = mpc5121_nfc_dev_ready; 702bf6065c6SBoris Brezillon chip->legacy.cmdfunc = mpc5121_nfc_command; 703716bbbabSBoris Brezillon chip->legacy.read_byte = mpc5121_nfc_read_byte; 704716bbbabSBoris Brezillon chip->legacy.read_buf = mpc5121_nfc_read_buf; 705716bbbabSBoris Brezillon chip->legacy.write_buf = mpc5121_nfc_write_buf; 7067d6c37e9SBoris Brezillon chip->legacy.select_chip = mpc5121_nfc_select_chip; 70745240367SBoris Brezillon chip->legacy.set_features = nand_get_set_features_notsupp; 70845240367SBoris Brezillon chip->legacy.get_features = nand_get_set_features_notsupp; 709bb9ebd4eSBrian Norris chip->bbt_options = NAND_BBT_USE_FLASH; 710bb315f74SAnatolij Gustschin 711bb315f74SAnatolij Gustschin /* Support external chip-select logic on ADS5121 board */ 71223819f2eSChristophe Jaillet if (of_machine_is_compatible("fsl,mpc5121ads")) { 713bb315f74SAnatolij Gustschin retval = ads5121_chipselect_init(mtd); 714bb315f74SAnatolij Gustschin if (retval) { 715bb315f74SAnatolij Gustschin dev_err(dev, "Chipselect init error!\n"); 716bb315f74SAnatolij Gustschin return retval; 717bb315f74SAnatolij Gustschin } 718bb315f74SAnatolij Gustschin 7197d6c37e9SBoris Brezillon chip->legacy.select_chip = ads5121_select_chip; 720bb315f74SAnatolij Gustschin } 721bb315f74SAnatolij Gustschin 722bb315f74SAnatolij Gustschin /* Enable NFC clock */ 72310de271fSGerhard Sittig clk = devm_clk_get(dev, "ipg"); 724180890c7SGerhard Sittig if (IS_ERR(clk)) { 725bb315f74SAnatolij Gustschin dev_err(dev, "Unable to acquire NFC clock!\n"); 726180890c7SGerhard Sittig retval = PTR_ERR(clk); 727bb315f74SAnatolij Gustschin goto error; 728bb315f74SAnatolij Gustschin } 729180890c7SGerhard Sittig retval = clk_prepare_enable(clk); 730180890c7SGerhard Sittig if (retval) { 731180890c7SGerhard Sittig dev_err(dev, "Unable to enable NFC clock!\n"); 732180890c7SGerhard Sittig goto error; 733180890c7SGerhard Sittig } 734180890c7SGerhard Sittig prv->clk = clk; 735bb315f74SAnatolij Gustschin 736bb315f74SAnatolij Gustschin /* Reset NAND Flash controller */ 737bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_RESET); 738bb315f74SAnatolij Gustschin while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) { 739bb315f74SAnatolij Gustschin if (resettime++ >= NFC_RESET_TIMEOUT) { 740bb315f74SAnatolij Gustschin dev_err(dev, "Timeout while resetting NFC!\n"); 741bb315f74SAnatolij Gustschin retval = -EINVAL; 742bb315f74SAnatolij Gustschin goto error; 743bb315f74SAnatolij Gustschin } 744bb315f74SAnatolij Gustschin 745bb315f74SAnatolij Gustschin udelay(1); 746bb315f74SAnatolij Gustschin } 747bb315f74SAnatolij Gustschin 748bb315f74SAnatolij Gustschin /* Enable write to NFC memory */ 749bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED); 750bb315f74SAnatolij Gustschin 751bb315f74SAnatolij Gustschin /* Enable write to all NAND pages */ 752bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000); 753bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF); 754bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK); 755bb315f74SAnatolij Gustschin 756bb315f74SAnatolij Gustschin /* 757bb315f74SAnatolij Gustschin * Setup NFC: 758bb315f74SAnatolij Gustschin * - Big Endian transfers, 759bb315f74SAnatolij Gustschin * - Interrupt after full page read/write. 760bb315f74SAnatolij Gustschin */ 761bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK | 762bb315f74SAnatolij Gustschin NFC_FULL_PAGE_INT); 763bb315f74SAnatolij Gustschin 764bb315f74SAnatolij Gustschin /* Set spare area size */ 765bb315f74SAnatolij Gustschin nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1); 766bb315f74SAnatolij Gustschin 767bb315f74SAnatolij Gustschin init_waitqueue_head(&prv->irq_waitq); 768bb315f74SAnatolij Gustschin retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME, 769bb315f74SAnatolij Gustschin mtd); 770bb315f74SAnatolij Gustschin if (retval) { 771bb315f74SAnatolij Gustschin dev_err(dev, "Error requesting IRQ!\n"); 772bb315f74SAnatolij Gustschin goto error; 773bb315f74SAnatolij Gustschin } 774bb315f74SAnatolij Gustschin 775bb315f74SAnatolij Gustschin /* Detect NAND chips */ 77600ad378fSBoris Brezillon retval = nand_scan(chip, be32_to_cpup(chips_no)); 777bbd4d03cSMasahiro Yamada if (retval) { 778bb315f74SAnatolij Gustschin dev_err(dev, "NAND Flash not found !\n"); 779bb315f74SAnatolij Gustschin goto error; 780bb315f74SAnatolij Gustschin } 781bb315f74SAnatolij Gustschin 782bb315f74SAnatolij Gustschin /* Set erase block size */ 783bb315f74SAnatolij Gustschin switch (mtd->erasesize / mtd->writesize) { 784bb315f74SAnatolij Gustschin case 32: 785bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32); 786bb315f74SAnatolij Gustschin break; 787bb315f74SAnatolij Gustschin 788bb315f74SAnatolij Gustschin case 64: 789bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64); 790bb315f74SAnatolij Gustschin break; 791bb315f74SAnatolij Gustschin 792bb315f74SAnatolij Gustschin case 128: 793bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128); 794bb315f74SAnatolij Gustschin break; 795bb315f74SAnatolij Gustschin 796bb315f74SAnatolij Gustschin case 256: 797bb315f74SAnatolij Gustschin nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256); 798bb315f74SAnatolij Gustschin break; 799bb315f74SAnatolij Gustschin 800bb315f74SAnatolij Gustschin default: 801bb315f74SAnatolij Gustschin dev_err(dev, "Unsupported NAND flash!\n"); 802bb315f74SAnatolij Gustschin retval = -ENXIO; 803bb315f74SAnatolij Gustschin goto error; 804bb315f74SAnatolij Gustschin } 805bb315f74SAnatolij Gustschin 806bb315f74SAnatolij Gustschin dev_set_drvdata(dev, mtd); 807bb315f74SAnatolij Gustschin 808bb315f74SAnatolij Gustschin /* Register device in MTD */ 809a61ae81aSBrian Norris retval = mtd_device_register(mtd, NULL, 0); 810bb315f74SAnatolij Gustschin if (retval) { 811bb315f74SAnatolij Gustschin dev_err(dev, "Error adding MTD device!\n"); 812bb315f74SAnatolij Gustschin goto error; 813bb315f74SAnatolij Gustschin } 814bb315f74SAnatolij Gustschin 815bb315f74SAnatolij Gustschin return 0; 816bb315f74SAnatolij Gustschin error: 817bb315f74SAnatolij Gustschin mpc5121_nfc_free(dev, mtd); 818bb315f74SAnatolij Gustschin return retval; 819bb315f74SAnatolij Gustschin } 820bb315f74SAnatolij Gustschin 821810b7e06SBill Pemberton static int mpc5121_nfc_remove(struct platform_device *op) 822bb315f74SAnatolij Gustschin { 823bb315f74SAnatolij Gustschin struct device *dev = &op->dev; 824bb315f74SAnatolij Gustschin struct mtd_info *mtd = dev_get_drvdata(dev); 8251a36a7f7SMiquel Raynal int ret; 826bb315f74SAnatolij Gustschin 8271a36a7f7SMiquel Raynal ret = mtd_device_unregister(mtd); 8281a36a7f7SMiquel Raynal WARN_ON(ret); 8291a36a7f7SMiquel Raynal nand_cleanup(mtd_to_nand(mtd)); 830bb315f74SAnatolij Gustschin mpc5121_nfc_free(dev, mtd); 831bb315f74SAnatolij Gustschin 832bb315f74SAnatolij Gustschin return 0; 833bb315f74SAnatolij Gustschin } 834bb315f74SAnatolij Gustschin 83566610443SFabian Frederick static const struct of_device_id mpc5121_nfc_match[] = { 836bb315f74SAnatolij Gustschin { .compatible = "fsl,mpc5121-nfc", }, 837bb315f74SAnatolij Gustschin {}, 838bb315f74SAnatolij Gustschin }; 8397446076eSLuis de Bethencourt MODULE_DEVICE_TABLE(of, mpc5121_nfc_match); 840bb315f74SAnatolij Gustschin 8411c48a5c9SGrant Likely static struct platform_driver mpc5121_nfc_driver = { 842bb315f74SAnatolij Gustschin .probe = mpc5121_nfc_probe, 8435153b88cSBill Pemberton .remove = mpc5121_nfc_remove, 844bb315f74SAnatolij Gustschin .driver = { 845bb315f74SAnatolij Gustschin .name = DRV_NAME, 84614acbbf8SAnatolij Gustschin .of_match_table = mpc5121_nfc_match, 847bb315f74SAnatolij Gustschin }, 848bb315f74SAnatolij Gustschin }; 849bb315f74SAnatolij Gustschin 850f99640deSAxel Lin module_platform_driver(mpc5121_nfc_driver); 851bb315f74SAnatolij Gustschin 852bb315f74SAnatolij Gustschin MODULE_AUTHOR("Freescale Semiconductor, Inc."); 853bb315f74SAnatolij Gustschin MODULE_DESCRIPTION("MPC5121 NAND MTD driver"); 854bb315f74SAnatolij Gustschin MODULE_LICENSE("GPL"); 855