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