18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2004-2008 Freescale Semiconductor, Inc. 48c2ecf20Sopenharmony_ci * Copyright 2009 Semihalf. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Approved as OSADL project by a majority of OSADL members and funded 78c2ecf20Sopenharmony_ci * by OSADL membership fees in 2009; for details see www.osadl.org. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on original driver from Freescale Semiconductor 108c2ecf20Sopenharmony_ci * written by John Rigby <jrigby@freescale.com> on basis of mxc_nand.c. 118c2ecf20Sopenharmony_ci * Reworked and extended by Piotr Ziecik <kosmo@semihalf.com>. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/clk.h> 168c2ecf20Sopenharmony_ci#include <linux/gfp.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/err.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/io.h> 218c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 228c2ecf20Sopenharmony_ci#include <linux/mtd/rawnand.h> 238c2ecf20Sopenharmony_ci#include <linux/mtd/partitions.h> 248c2ecf20Sopenharmony_ci#include <linux/of_address.h> 258c2ecf20Sopenharmony_ci#include <linux/of_device.h> 268c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 278c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <asm/mpc5121.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* Addresses for NFC MAIN RAM BUFFER areas */ 328c2ecf20Sopenharmony_ci#define NFC_MAIN_AREA(n) ((n) * 0x200) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Addresses for NFC SPARE BUFFER areas */ 358c2ecf20Sopenharmony_ci#define NFC_SPARE_BUFFERS 8 368c2ecf20Sopenharmony_ci#define NFC_SPARE_LEN 0x40 378c2ecf20Sopenharmony_ci#define NFC_SPARE_AREA(n) (0x1000 + ((n) * NFC_SPARE_LEN)) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* MPC5121 NFC registers */ 408c2ecf20Sopenharmony_ci#define NFC_BUF_ADDR 0x1E04 418c2ecf20Sopenharmony_ci#define NFC_FLASH_ADDR 0x1E06 428c2ecf20Sopenharmony_ci#define NFC_FLASH_CMD 0x1E08 438c2ecf20Sopenharmony_ci#define NFC_CONFIG 0x1E0A 448c2ecf20Sopenharmony_ci#define NFC_ECC_STATUS1 0x1E0C 458c2ecf20Sopenharmony_ci#define NFC_ECC_STATUS2 0x1E0E 468c2ecf20Sopenharmony_ci#define NFC_SPAS 0x1E10 478c2ecf20Sopenharmony_ci#define NFC_WRPROT 0x1E12 488c2ecf20Sopenharmony_ci#define NFC_NF_WRPRST 0x1E18 498c2ecf20Sopenharmony_ci#define NFC_CONFIG1 0x1E1A 508c2ecf20Sopenharmony_ci#define NFC_CONFIG2 0x1E1C 518c2ecf20Sopenharmony_ci#define NFC_UNLOCKSTART_BLK0 0x1E20 528c2ecf20Sopenharmony_ci#define NFC_UNLOCKEND_BLK0 0x1E22 538c2ecf20Sopenharmony_ci#define NFC_UNLOCKSTART_BLK1 0x1E24 548c2ecf20Sopenharmony_ci#define NFC_UNLOCKEND_BLK1 0x1E26 558c2ecf20Sopenharmony_ci#define NFC_UNLOCKSTART_BLK2 0x1E28 568c2ecf20Sopenharmony_ci#define NFC_UNLOCKEND_BLK2 0x1E2A 578c2ecf20Sopenharmony_ci#define NFC_UNLOCKSTART_BLK3 0x1E2C 588c2ecf20Sopenharmony_ci#define NFC_UNLOCKEND_BLK3 0x1E2E 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* Bit Definitions: NFC_BUF_ADDR */ 618c2ecf20Sopenharmony_ci#define NFC_RBA_MASK (7 << 0) 628c2ecf20Sopenharmony_ci#define NFC_ACTIVE_CS_SHIFT 5 638c2ecf20Sopenharmony_ci#define NFC_ACTIVE_CS_MASK (3 << NFC_ACTIVE_CS_SHIFT) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Bit Definitions: NFC_CONFIG */ 668c2ecf20Sopenharmony_ci#define NFC_BLS_UNLOCKED (1 << 1) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Bit Definitions: NFC_CONFIG1 */ 698c2ecf20Sopenharmony_ci#define NFC_ECC_4BIT (1 << 0) 708c2ecf20Sopenharmony_ci#define NFC_FULL_PAGE_DMA (1 << 1) 718c2ecf20Sopenharmony_ci#define NFC_SPARE_ONLY (1 << 2) 728c2ecf20Sopenharmony_ci#define NFC_ECC_ENABLE (1 << 3) 738c2ecf20Sopenharmony_ci#define NFC_INT_MASK (1 << 4) 748c2ecf20Sopenharmony_ci#define NFC_BIG_ENDIAN (1 << 5) 758c2ecf20Sopenharmony_ci#define NFC_RESET (1 << 6) 768c2ecf20Sopenharmony_ci#define NFC_CE (1 << 7) 778c2ecf20Sopenharmony_ci#define NFC_ONE_CYCLE (1 << 8) 788c2ecf20Sopenharmony_ci#define NFC_PPB_32 (0 << 9) 798c2ecf20Sopenharmony_ci#define NFC_PPB_64 (1 << 9) 808c2ecf20Sopenharmony_ci#define NFC_PPB_128 (2 << 9) 818c2ecf20Sopenharmony_ci#define NFC_PPB_256 (3 << 9) 828c2ecf20Sopenharmony_ci#define NFC_PPB_MASK (3 << 9) 838c2ecf20Sopenharmony_ci#define NFC_FULL_PAGE_INT (1 << 11) 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* Bit Definitions: NFC_CONFIG2 */ 868c2ecf20Sopenharmony_ci#define NFC_COMMAND (1 << 0) 878c2ecf20Sopenharmony_ci#define NFC_ADDRESS (1 << 1) 888c2ecf20Sopenharmony_ci#define NFC_INPUT (1 << 2) 898c2ecf20Sopenharmony_ci#define NFC_OUTPUT (1 << 3) 908c2ecf20Sopenharmony_ci#define NFC_ID (1 << 4) 918c2ecf20Sopenharmony_ci#define NFC_STATUS (1 << 5) 928c2ecf20Sopenharmony_ci#define NFC_CMD_FAIL (1 << 15) 938c2ecf20Sopenharmony_ci#define NFC_INT (1 << 15) 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* Bit Definitions: NFC_WRPROT */ 968c2ecf20Sopenharmony_ci#define NFC_WPC_LOCK_TIGHT (1 << 0) 978c2ecf20Sopenharmony_ci#define NFC_WPC_LOCK (1 << 1) 988c2ecf20Sopenharmony_ci#define NFC_WPC_UNLOCK (1 << 2) 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define DRV_NAME "mpc5121_nfc" 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* Timeouts */ 1038c2ecf20Sopenharmony_ci#define NFC_RESET_TIMEOUT 1000 /* 1 ms */ 1048c2ecf20Sopenharmony_ci#define NFC_TIMEOUT (HZ / 10) /* 1/10 s */ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistruct mpc5121_nfc_prv { 1078c2ecf20Sopenharmony_ci struct nand_controller controller; 1088c2ecf20Sopenharmony_ci struct nand_chip chip; 1098c2ecf20Sopenharmony_ci int irq; 1108c2ecf20Sopenharmony_ci void __iomem *regs; 1118c2ecf20Sopenharmony_ci struct clk *clk; 1128c2ecf20Sopenharmony_ci wait_queue_head_t irq_waitq; 1138c2ecf20Sopenharmony_ci uint column; 1148c2ecf20Sopenharmony_ci int spareonly; 1158c2ecf20Sopenharmony_ci void __iomem *csreg; 1168c2ecf20Sopenharmony_ci struct device *dev; 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic void mpc5121_nfc_done(struct mtd_info *mtd); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* Read NFC register */ 1228c2ecf20Sopenharmony_cistatic inline u16 nfc_read(struct mtd_info *mtd, uint reg) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 1258c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return in_be16(prv->regs + reg); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* Write NFC register */ 1318c2ecf20Sopenharmony_cistatic inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 1348c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci out_be16(prv->regs + reg, val); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* Set bits in NFC register */ 1408c2ecf20Sopenharmony_cistatic inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci nfc_write(mtd, reg, nfc_read(mtd, reg) | bits); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/* Clear bits in NFC register */ 1468c2ecf20Sopenharmony_cistatic inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* Invoke address cycle */ 1528c2ecf20Sopenharmony_cistatic inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_FLASH_ADDR, addr); 1558c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS); 1568c2ecf20Sopenharmony_ci mpc5121_nfc_done(mtd); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* Invoke command cycle */ 1608c2ecf20Sopenharmony_cistatic inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_FLASH_CMD, cmd); 1638c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND); 1648c2ecf20Sopenharmony_ci mpc5121_nfc_done(mtd); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* Send data from NFC buffers to NAND flash */ 1688c2ecf20Sopenharmony_cistatic inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 1718c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_CONFIG2, NFC_INPUT); 1728c2ecf20Sopenharmony_ci mpc5121_nfc_done(mtd); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* Receive data from NAND flash */ 1768c2ecf20Sopenharmony_cistatic inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 1798c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT); 1808c2ecf20Sopenharmony_ci mpc5121_nfc_done(mtd); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* Receive ID from NAND flash */ 1848c2ecf20Sopenharmony_cistatic inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 1878c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_CONFIG2, NFC_ID); 1888c2ecf20Sopenharmony_ci mpc5121_nfc_done(mtd); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* Receive status from NAND flash */ 1928c2ecf20Sopenharmony_cistatic inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK); 1958c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_CONFIG2, NFC_STATUS); 1968c2ecf20Sopenharmony_ci mpc5121_nfc_done(mtd); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* NFC interrupt handler */ 2008c2ecf20Sopenharmony_cistatic irqreturn_t mpc5121_nfc_irq(int irq, void *data) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct mtd_info *mtd = data; 2038c2ecf20Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 2048c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK); 2078c2ecf20Sopenharmony_ci wake_up(&prv->irq_waitq); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/* Wait for operation complete */ 2138c2ecf20Sopenharmony_cistatic void mpc5121_nfc_done(struct mtd_info *mtd) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 2168c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 2178c2ecf20Sopenharmony_ci int rv; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) { 2208c2ecf20Sopenharmony_ci nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK); 2218c2ecf20Sopenharmony_ci rv = wait_event_timeout(prv->irq_waitq, 2228c2ecf20Sopenharmony_ci (nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (!rv) 2258c2ecf20Sopenharmony_ci dev_warn(prv->dev, 2268c2ecf20Sopenharmony_ci "Timeout while waiting for interrupt.\n"); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci nfc_clear(mtd, NFC_CONFIG2, NFC_INT); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/* Do address cycle(s) */ 2338c2ecf20Sopenharmony_cistatic void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 2368c2ecf20Sopenharmony_ci u32 pagemask = chip->pagemask; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (column != -1) { 2398c2ecf20Sopenharmony_ci mpc5121_nfc_send_addr(mtd, column); 2408c2ecf20Sopenharmony_ci if (mtd->writesize > 512) 2418c2ecf20Sopenharmony_ci mpc5121_nfc_send_addr(mtd, column >> 8); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (page != -1) { 2458c2ecf20Sopenharmony_ci do { 2468c2ecf20Sopenharmony_ci mpc5121_nfc_send_addr(mtd, page & 0xFF); 2478c2ecf20Sopenharmony_ci page >>= 8; 2488c2ecf20Sopenharmony_ci pagemask >>= 8; 2498c2ecf20Sopenharmony_ci } while (pagemask); 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* Control chip select signals */ 2548c2ecf20Sopenharmony_cistatic void mpc5121_nfc_select_chip(struct nand_chip *nand, int chip) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(nand); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (chip < 0) { 2598c2ecf20Sopenharmony_ci nfc_clear(mtd, NFC_CONFIG1, NFC_CE); 2608c2ecf20Sopenharmony_ci return; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK); 2648c2ecf20Sopenharmony_ci nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) & 2658c2ecf20Sopenharmony_ci NFC_ACTIVE_CS_MASK); 2668c2ecf20Sopenharmony_ci nfc_set(mtd, NFC_CONFIG1, NFC_CE); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/* Init external chip select logic on ADS5121 board */ 2708c2ecf20Sopenharmony_cistatic int ads5121_chipselect_init(struct mtd_info *mtd) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 2738c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 2748c2ecf20Sopenharmony_ci struct device_node *dn; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld"); 2778c2ecf20Sopenharmony_ci if (dn) { 2788c2ecf20Sopenharmony_ci prv->csreg = of_iomap(dn, 0); 2798c2ecf20Sopenharmony_ci of_node_put(dn); 2808c2ecf20Sopenharmony_ci if (!prv->csreg) 2818c2ecf20Sopenharmony_ci return -ENOMEM; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* CPLD Register 9 controls NAND /CE Lines */ 2848c2ecf20Sopenharmony_ci prv->csreg += 9; 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci return -EINVAL; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci/* Control chips select signal on ADS5121 board */ 2928c2ecf20Sopenharmony_cistatic void ads5121_select_chip(struct nand_chip *nand, int chip) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand); 2958c2ecf20Sopenharmony_ci u8 v; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci v = in_8(prv->csreg); 2988c2ecf20Sopenharmony_ci v |= 0x0F; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (chip >= 0) { 3018c2ecf20Sopenharmony_ci mpc5121_nfc_select_chip(nand, 0); 3028c2ecf20Sopenharmony_ci v &= ~(1 << chip); 3038c2ecf20Sopenharmony_ci } else 3048c2ecf20Sopenharmony_ci mpc5121_nfc_select_chip(nand, -1); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci out_8(prv->csreg, v); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* Read NAND Ready/Busy signal */ 3108c2ecf20Sopenharmony_cistatic int mpc5121_nfc_dev_ready(struct nand_chip *nand) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * NFC handles ready/busy signal internally. Therefore, this function 3148c2ecf20Sopenharmony_ci * always returns status as ready. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci return 1; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/* Write command to NAND flash */ 3208c2ecf20Sopenharmony_cistatic void mpc5121_nfc_command(struct nand_chip *chip, unsigned command, 3218c2ecf20Sopenharmony_ci int column, int page) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct mtd_info *mtd = nand_to_mtd(chip); 3248c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci prv->column = (column >= 0) ? column : 0; 3278c2ecf20Sopenharmony_ci prv->spareonly = 0; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci switch (command) { 3308c2ecf20Sopenharmony_ci case NAND_CMD_PAGEPROG: 3318c2ecf20Sopenharmony_ci mpc5121_nfc_send_prog_page(mtd); 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci /* 3348c2ecf20Sopenharmony_ci * NFC does not support sub-page reads and writes, 3358c2ecf20Sopenharmony_ci * so emulate them using full page transfers. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci case NAND_CMD_READ0: 3388c2ecf20Sopenharmony_ci column = 0; 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci case NAND_CMD_READ1: 3428c2ecf20Sopenharmony_ci prv->column += 256; 3438c2ecf20Sopenharmony_ci command = NAND_CMD_READ0; 3448c2ecf20Sopenharmony_ci column = 0; 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci case NAND_CMD_READOOB: 3488c2ecf20Sopenharmony_ci prv->spareonly = 1; 3498c2ecf20Sopenharmony_ci command = NAND_CMD_READ0; 3508c2ecf20Sopenharmony_ci column = 0; 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci case NAND_CMD_SEQIN: 3548c2ecf20Sopenharmony_ci mpc5121_nfc_command(chip, NAND_CMD_READ0, column, page); 3558c2ecf20Sopenharmony_ci column = 0; 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci case NAND_CMD_ERASE1: 3598c2ecf20Sopenharmony_ci case NAND_CMD_ERASE2: 3608c2ecf20Sopenharmony_ci case NAND_CMD_READID: 3618c2ecf20Sopenharmony_ci case NAND_CMD_STATUS: 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci default: 3658c2ecf20Sopenharmony_ci return; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci mpc5121_nfc_send_cmd(mtd, command); 3698c2ecf20Sopenharmony_ci mpc5121_nfc_addr_cycle(mtd, column, page); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci switch (command) { 3728c2ecf20Sopenharmony_ci case NAND_CMD_READ0: 3738c2ecf20Sopenharmony_ci if (mtd->writesize > 512) 3748c2ecf20Sopenharmony_ci mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART); 3758c2ecf20Sopenharmony_ci mpc5121_nfc_send_read_page(mtd); 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci case NAND_CMD_READID: 3798c2ecf20Sopenharmony_ci mpc5121_nfc_send_read_id(mtd); 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci case NAND_CMD_STATUS: 3838c2ecf20Sopenharmony_ci mpc5121_nfc_send_read_status(mtd); 3848c2ecf20Sopenharmony_ci if (chip->options & NAND_BUSWIDTH_16) 3858c2ecf20Sopenharmony_ci prv->column = 1; 3868c2ecf20Sopenharmony_ci else 3878c2ecf20Sopenharmony_ci prv->column = 0; 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/* Copy data from/to NFC spare buffers. */ 3938c2ecf20Sopenharmony_cistatic void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset, 3948c2ecf20Sopenharmony_ci u8 *buffer, uint size, int wr) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct nand_chip *nand = mtd_to_nand(mtd); 3978c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand); 3988c2ecf20Sopenharmony_ci uint o, s, sbsize, blksize; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* 4018c2ecf20Sopenharmony_ci * NAND spare area is available through NFC spare buffers. 4028c2ecf20Sopenharmony_ci * The NFC divides spare area into (page_size / 512) chunks. 4038c2ecf20Sopenharmony_ci * Each chunk is placed into separate spare memory area, using 4048c2ecf20Sopenharmony_ci * first (spare_size / num_of_chunks) bytes of the buffer. 4058c2ecf20Sopenharmony_ci * 4068c2ecf20Sopenharmony_ci * For NAND device in which the spare area is not divided fully 4078c2ecf20Sopenharmony_ci * by the number of chunks, number of used bytes in each spare 4088c2ecf20Sopenharmony_ci * buffer is rounded down to the nearest even number of bytes, 4098c2ecf20Sopenharmony_ci * and all remaining bytes are added to the last used spare area. 4108c2ecf20Sopenharmony_ci * 4118c2ecf20Sopenharmony_ci * For more information read section 26.6.10 of MPC5121e 4128c2ecf20Sopenharmony_ci * Microcontroller Reference Manual, Rev. 3. 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* Calculate number of valid bytes in each spare buffer */ 4168c2ecf20Sopenharmony_ci sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci while (size) { 4198c2ecf20Sopenharmony_ci /* Calculate spare buffer number */ 4208c2ecf20Sopenharmony_ci s = offset / sbsize; 4218c2ecf20Sopenharmony_ci if (s > NFC_SPARE_BUFFERS - 1) 4228c2ecf20Sopenharmony_ci s = NFC_SPARE_BUFFERS - 1; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* 4258c2ecf20Sopenharmony_ci * Calculate offset to requested data block in selected spare 4268c2ecf20Sopenharmony_ci * buffer and its size. 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ci o = offset - (s * sbsize); 4298c2ecf20Sopenharmony_ci blksize = min(sbsize - o, size); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (wr) 4328c2ecf20Sopenharmony_ci memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o, 4338c2ecf20Sopenharmony_ci buffer, blksize); 4348c2ecf20Sopenharmony_ci else 4358c2ecf20Sopenharmony_ci memcpy_fromio(buffer, 4368c2ecf20Sopenharmony_ci prv->regs + NFC_SPARE_AREA(s) + o, blksize); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci buffer += blksize; 4398c2ecf20Sopenharmony_ci offset += blksize; 4408c2ecf20Sopenharmony_ci size -= blksize; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/* Copy data from/to NFC main and spare buffers */ 4458c2ecf20Sopenharmony_cistatic void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len, 4468c2ecf20Sopenharmony_ci int wr) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 4498c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 4508c2ecf20Sopenharmony_ci uint c = prv->column; 4518c2ecf20Sopenharmony_ci uint l; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* Handle spare area access */ 4548c2ecf20Sopenharmony_ci if (prv->spareonly || c >= mtd->writesize) { 4558c2ecf20Sopenharmony_ci /* Calculate offset from beginning of spare area */ 4568c2ecf20Sopenharmony_ci if (c >= mtd->writesize) 4578c2ecf20Sopenharmony_ci c -= mtd->writesize; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci prv->column += len; 4608c2ecf20Sopenharmony_ci mpc5121_nfc_copy_spare(mtd, c, buf, len, wr); 4618c2ecf20Sopenharmony_ci return; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* 4658c2ecf20Sopenharmony_ci * Handle main area access - limit copy length to prevent 4668c2ecf20Sopenharmony_ci * crossing main/spare boundary. 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci l = min((uint)len, mtd->writesize - c); 4698c2ecf20Sopenharmony_ci prv->column += l; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (wr) 4728c2ecf20Sopenharmony_ci memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l); 4738c2ecf20Sopenharmony_ci else 4748c2ecf20Sopenharmony_ci memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Handle crossing main/spare boundary */ 4778c2ecf20Sopenharmony_ci if (l != len) { 4788c2ecf20Sopenharmony_ci buf += l; 4798c2ecf20Sopenharmony_ci len -= l; 4808c2ecf20Sopenharmony_ci mpc5121_nfc_buf_copy(mtd, buf, len, wr); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci/* Read data from NFC buffers */ 4858c2ecf20Sopenharmony_cistatic void mpc5121_nfc_read_buf(struct nand_chip *chip, u_char *buf, int len) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci mpc5121_nfc_buf_copy(nand_to_mtd(chip), buf, len, 0); 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/* Write data to NFC buffers */ 4918c2ecf20Sopenharmony_cistatic void mpc5121_nfc_write_buf(struct nand_chip *chip, const u_char *buf, 4928c2ecf20Sopenharmony_ci int len) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci mpc5121_nfc_buf_copy(nand_to_mtd(chip), (u_char *)buf, len, 1); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci/* Read byte from NFC buffers */ 4988c2ecf20Sopenharmony_cistatic u8 mpc5121_nfc_read_byte(struct nand_chip *chip) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci u8 tmp; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci mpc5121_nfc_read_buf(chip, &tmp, sizeof(tmp)); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return tmp; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/* 5088c2ecf20Sopenharmony_ci * Read NFC configuration from Reset Config Word 5098c2ecf20Sopenharmony_ci * 5108c2ecf20Sopenharmony_ci * NFC is configured during reset in basis of information stored 5118c2ecf20Sopenharmony_ci * in Reset Config Word. There is no other way to set NAND block 5128c2ecf20Sopenharmony_ci * size, spare size and bus width. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_cistatic int mpc5121_nfc_read_hw_config(struct mtd_info *mtd) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 5178c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 5188c2ecf20Sopenharmony_ci struct mpc512x_reset_module *rm; 5198c2ecf20Sopenharmony_ci struct device_node *rmnode; 5208c2ecf20Sopenharmony_ci uint rcw_pagesize = 0; 5218c2ecf20Sopenharmony_ci uint rcw_sparesize = 0; 5228c2ecf20Sopenharmony_ci uint rcw_width; 5238c2ecf20Sopenharmony_ci uint rcwh; 5248c2ecf20Sopenharmony_ci uint romloc, ps; 5258c2ecf20Sopenharmony_ci int ret = 0; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset"); 5288c2ecf20Sopenharmony_ci if (!rmnode) { 5298c2ecf20Sopenharmony_ci dev_err(prv->dev, "Missing 'fsl,mpc5121-reset' " 5308c2ecf20Sopenharmony_ci "node in device tree!\n"); 5318c2ecf20Sopenharmony_ci return -ENODEV; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci rm = of_iomap(rmnode, 0); 5358c2ecf20Sopenharmony_ci if (!rm) { 5368c2ecf20Sopenharmony_ci dev_err(prv->dev, "Error mapping reset module node!\n"); 5378c2ecf20Sopenharmony_ci ret = -EBUSY; 5388c2ecf20Sopenharmony_ci goto out; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci rcwh = in_be32(&rm->rcwhr); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* Bit 6: NFC bus width */ 5448c2ecf20Sopenharmony_ci rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* Bit 7: NFC Page/Spare size */ 5478c2ecf20Sopenharmony_ci ps = (rcwh >> 7) & 0x1; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* Bits [22:21]: ROM Location */ 5508c2ecf20Sopenharmony_ci romloc = (rcwh >> 21) & 0x3; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* Decode RCW bits */ 5538c2ecf20Sopenharmony_ci switch ((ps << 2) | romloc) { 5548c2ecf20Sopenharmony_ci case 0x00: 5558c2ecf20Sopenharmony_ci case 0x01: 5568c2ecf20Sopenharmony_ci rcw_pagesize = 512; 5578c2ecf20Sopenharmony_ci rcw_sparesize = 16; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci case 0x02: 5608c2ecf20Sopenharmony_ci case 0x03: 5618c2ecf20Sopenharmony_ci rcw_pagesize = 4096; 5628c2ecf20Sopenharmony_ci rcw_sparesize = 128; 5638c2ecf20Sopenharmony_ci break; 5648c2ecf20Sopenharmony_ci case 0x04: 5658c2ecf20Sopenharmony_ci case 0x05: 5668c2ecf20Sopenharmony_ci rcw_pagesize = 2048; 5678c2ecf20Sopenharmony_ci rcw_sparesize = 64; 5688c2ecf20Sopenharmony_ci break; 5698c2ecf20Sopenharmony_ci case 0x06: 5708c2ecf20Sopenharmony_ci case 0x07: 5718c2ecf20Sopenharmony_ci rcw_pagesize = 4096; 5728c2ecf20Sopenharmony_ci rcw_sparesize = 218; 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci mtd->writesize = rcw_pagesize; 5778c2ecf20Sopenharmony_ci mtd->oobsize = rcw_sparesize; 5788c2ecf20Sopenharmony_ci if (rcw_width == 2) 5798c2ecf20Sopenharmony_ci chip->options |= NAND_BUSWIDTH_16; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci dev_notice(prv->dev, "Configured for " 5828c2ecf20Sopenharmony_ci "%u-bit NAND, page size %u " 5838c2ecf20Sopenharmony_ci "with %u spare.\n", 5848c2ecf20Sopenharmony_ci rcw_width * 8, rcw_pagesize, 5858c2ecf20Sopenharmony_ci rcw_sparesize); 5868c2ecf20Sopenharmony_ci iounmap(rm); 5878c2ecf20Sopenharmony_ciout: 5888c2ecf20Sopenharmony_ci of_node_put(rmnode); 5898c2ecf20Sopenharmony_ci return ret; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/* Free driver resources */ 5938c2ecf20Sopenharmony_cistatic void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci struct nand_chip *chip = mtd_to_nand(mtd); 5968c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (prv->clk) 5998c2ecf20Sopenharmony_ci clk_disable_unprepare(prv->clk); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (prv->csreg) 6028c2ecf20Sopenharmony_ci iounmap(prv->csreg); 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int mpc5121_nfc_attach_chip(struct nand_chip *chip) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT && 6088c2ecf20Sopenharmony_ci chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN) 6098c2ecf20Sopenharmony_ci chip->ecc.algo = NAND_ECC_ALGO_HAMMING; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return 0; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic const struct nand_controller_ops mpc5121_nfc_ops = { 6158c2ecf20Sopenharmony_ci .attach_chip = mpc5121_nfc_attach_chip, 6168c2ecf20Sopenharmony_ci}; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int mpc5121_nfc_probe(struct platform_device *op) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci struct device_node *dn = op->dev.of_node; 6218c2ecf20Sopenharmony_ci struct clk *clk; 6228c2ecf20Sopenharmony_ci struct device *dev = &op->dev; 6238c2ecf20Sopenharmony_ci struct mpc5121_nfc_prv *prv; 6248c2ecf20Sopenharmony_ci struct resource res; 6258c2ecf20Sopenharmony_ci struct mtd_info *mtd; 6268c2ecf20Sopenharmony_ci struct nand_chip *chip; 6278c2ecf20Sopenharmony_ci unsigned long regs_paddr, regs_size; 6288c2ecf20Sopenharmony_ci const __be32 *chips_no; 6298c2ecf20Sopenharmony_ci int resettime = 0; 6308c2ecf20Sopenharmony_ci int retval = 0; 6318c2ecf20Sopenharmony_ci int rev, len; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* 6348c2ecf20Sopenharmony_ci * Check SoC revision. This driver supports only NFC 6358c2ecf20Sopenharmony_ci * in MPC5121 revision 2 and MPC5123 revision 3. 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_ci rev = (mfspr(SPRN_SVR) >> 4) & 0xF; 6388c2ecf20Sopenharmony_ci if ((rev != 2) && (rev != 3)) { 6398c2ecf20Sopenharmony_ci dev_err(dev, "SoC revision %u is not supported!\n", rev); 6408c2ecf20Sopenharmony_ci return -ENXIO; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL); 6448c2ecf20Sopenharmony_ci if (!prv) 6458c2ecf20Sopenharmony_ci return -ENOMEM; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci chip = &prv->chip; 6488c2ecf20Sopenharmony_ci mtd = nand_to_mtd(chip); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci nand_controller_init(&prv->controller); 6518c2ecf20Sopenharmony_ci prv->controller.ops = &mpc5121_nfc_ops; 6528c2ecf20Sopenharmony_ci chip->controller = &prv->controller; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci mtd->dev.parent = dev; 6558c2ecf20Sopenharmony_ci nand_set_controller_data(chip, prv); 6568c2ecf20Sopenharmony_ci nand_set_flash_node(chip, dn); 6578c2ecf20Sopenharmony_ci prv->dev = dev; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* Read NFC configuration from Reset Config Word */ 6608c2ecf20Sopenharmony_ci retval = mpc5121_nfc_read_hw_config(mtd); 6618c2ecf20Sopenharmony_ci if (retval) { 6628c2ecf20Sopenharmony_ci dev_err(dev, "Unable to read NFC config!\n"); 6638c2ecf20Sopenharmony_ci return retval; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci prv->irq = irq_of_parse_and_map(dn, 0); 6678c2ecf20Sopenharmony_ci if (prv->irq == NO_IRQ) { 6688c2ecf20Sopenharmony_ci dev_err(dev, "Error mapping IRQ!\n"); 6698c2ecf20Sopenharmony_ci return -EINVAL; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci retval = of_address_to_resource(dn, 0, &res); 6738c2ecf20Sopenharmony_ci if (retval) { 6748c2ecf20Sopenharmony_ci dev_err(dev, "Error parsing memory region!\n"); 6758c2ecf20Sopenharmony_ci return retval; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci chips_no = of_get_property(dn, "chips", &len); 6798c2ecf20Sopenharmony_ci if (!chips_no || len != sizeof(*chips_no)) { 6808c2ecf20Sopenharmony_ci dev_err(dev, "Invalid/missing 'chips' property!\n"); 6818c2ecf20Sopenharmony_ci return -EINVAL; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci regs_paddr = res.start; 6858c2ecf20Sopenharmony_ci regs_size = resource_size(&res); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) { 6888c2ecf20Sopenharmony_ci dev_err(dev, "Error requesting memory region!\n"); 6898c2ecf20Sopenharmony_ci return -EBUSY; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci prv->regs = devm_ioremap(dev, regs_paddr, regs_size); 6938c2ecf20Sopenharmony_ci if (!prv->regs) { 6948c2ecf20Sopenharmony_ci dev_err(dev, "Error mapping memory region!\n"); 6958c2ecf20Sopenharmony_ci return -ENOMEM; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci mtd->name = "MPC5121 NAND"; 6998c2ecf20Sopenharmony_ci chip->legacy.dev_ready = mpc5121_nfc_dev_ready; 7008c2ecf20Sopenharmony_ci chip->legacy.cmdfunc = mpc5121_nfc_command; 7018c2ecf20Sopenharmony_ci chip->legacy.read_byte = mpc5121_nfc_read_byte; 7028c2ecf20Sopenharmony_ci chip->legacy.read_buf = mpc5121_nfc_read_buf; 7038c2ecf20Sopenharmony_ci chip->legacy.write_buf = mpc5121_nfc_write_buf; 7048c2ecf20Sopenharmony_ci chip->legacy.select_chip = mpc5121_nfc_select_chip; 7058c2ecf20Sopenharmony_ci chip->legacy.set_features = nand_get_set_features_notsupp; 7068c2ecf20Sopenharmony_ci chip->legacy.get_features = nand_get_set_features_notsupp; 7078c2ecf20Sopenharmony_ci chip->bbt_options = NAND_BBT_USE_FLASH; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* Support external chip-select logic on ADS5121 board */ 7108c2ecf20Sopenharmony_ci if (of_machine_is_compatible("fsl,mpc5121ads")) { 7118c2ecf20Sopenharmony_ci retval = ads5121_chipselect_init(mtd); 7128c2ecf20Sopenharmony_ci if (retval) { 7138c2ecf20Sopenharmony_ci dev_err(dev, "Chipselect init error!\n"); 7148c2ecf20Sopenharmony_ci return retval; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci chip->legacy.select_chip = ads5121_select_chip; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci /* Enable NFC clock */ 7218c2ecf20Sopenharmony_ci clk = devm_clk_get(dev, "ipg"); 7228c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 7238c2ecf20Sopenharmony_ci dev_err(dev, "Unable to acquire NFC clock!\n"); 7248c2ecf20Sopenharmony_ci retval = PTR_ERR(clk); 7258c2ecf20Sopenharmony_ci goto error; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci retval = clk_prepare_enable(clk); 7288c2ecf20Sopenharmony_ci if (retval) { 7298c2ecf20Sopenharmony_ci dev_err(dev, "Unable to enable NFC clock!\n"); 7308c2ecf20Sopenharmony_ci goto error; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci prv->clk = clk; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* Reset NAND Flash controller */ 7358c2ecf20Sopenharmony_ci nfc_set(mtd, NFC_CONFIG1, NFC_RESET); 7368c2ecf20Sopenharmony_ci while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) { 7378c2ecf20Sopenharmony_ci if (resettime++ >= NFC_RESET_TIMEOUT) { 7388c2ecf20Sopenharmony_ci dev_err(dev, "Timeout while resetting NFC!\n"); 7398c2ecf20Sopenharmony_ci retval = -EINVAL; 7408c2ecf20Sopenharmony_ci goto error; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci udelay(1); 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* Enable write to NFC memory */ 7478c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* Enable write to all NAND pages */ 7508c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000); 7518c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF); 7528c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* 7558c2ecf20Sopenharmony_ci * Setup NFC: 7568c2ecf20Sopenharmony_ci * - Big Endian transfers, 7578c2ecf20Sopenharmony_ci * - Interrupt after full page read/write. 7588c2ecf20Sopenharmony_ci */ 7598c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK | 7608c2ecf20Sopenharmony_ci NFC_FULL_PAGE_INT); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* Set spare area size */ 7638c2ecf20Sopenharmony_ci nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci init_waitqueue_head(&prv->irq_waitq); 7668c2ecf20Sopenharmony_ci retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME, 7678c2ecf20Sopenharmony_ci mtd); 7688c2ecf20Sopenharmony_ci if (retval) { 7698c2ecf20Sopenharmony_ci dev_err(dev, "Error requesting IRQ!\n"); 7708c2ecf20Sopenharmony_ci goto error; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* 7748c2ecf20Sopenharmony_ci * This driver assumes that the default ECC engine should be TYPE_SOFT. 7758c2ecf20Sopenharmony_ci * Set ->engine_type before registering the NAND devices in order to 7768c2ecf20Sopenharmony_ci * provide a driver specific default value. 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_ci chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* Detect NAND chips */ 7818c2ecf20Sopenharmony_ci retval = nand_scan(chip, be32_to_cpup(chips_no)); 7828c2ecf20Sopenharmony_ci if (retval) { 7838c2ecf20Sopenharmony_ci dev_err(dev, "NAND Flash not found !\n"); 7848c2ecf20Sopenharmony_ci goto error; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci /* Set erase block size */ 7888c2ecf20Sopenharmony_ci switch (mtd->erasesize / mtd->writesize) { 7898c2ecf20Sopenharmony_ci case 32: 7908c2ecf20Sopenharmony_ci nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32); 7918c2ecf20Sopenharmony_ci break; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci case 64: 7948c2ecf20Sopenharmony_ci nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64); 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci case 128: 7988c2ecf20Sopenharmony_ci nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128); 7998c2ecf20Sopenharmony_ci break; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci case 256: 8028c2ecf20Sopenharmony_ci nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256); 8038c2ecf20Sopenharmony_ci break; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci default: 8068c2ecf20Sopenharmony_ci dev_err(dev, "Unsupported NAND flash!\n"); 8078c2ecf20Sopenharmony_ci retval = -ENXIO; 8088c2ecf20Sopenharmony_ci goto error; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci dev_set_drvdata(dev, mtd); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci /* Register device in MTD */ 8148c2ecf20Sopenharmony_ci retval = mtd_device_register(mtd, NULL, 0); 8158c2ecf20Sopenharmony_ci if (retval) { 8168c2ecf20Sopenharmony_ci dev_err(dev, "Error adding MTD device!\n"); 8178c2ecf20Sopenharmony_ci goto error; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci return 0; 8218c2ecf20Sopenharmony_cierror: 8228c2ecf20Sopenharmony_ci mpc5121_nfc_free(dev, mtd); 8238c2ecf20Sopenharmony_ci return retval; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic int mpc5121_nfc_remove(struct platform_device *op) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct device *dev = &op->dev; 8298c2ecf20Sopenharmony_ci struct mtd_info *mtd = dev_get_drvdata(dev); 8308c2ecf20Sopenharmony_ci int ret; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci ret = mtd_device_unregister(mtd); 8338c2ecf20Sopenharmony_ci WARN_ON(ret); 8348c2ecf20Sopenharmony_ci nand_cleanup(mtd_to_nand(mtd)); 8358c2ecf20Sopenharmony_ci mpc5121_nfc_free(dev, mtd); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci return 0; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic const struct of_device_id mpc5121_nfc_match[] = { 8418c2ecf20Sopenharmony_ci { .compatible = "fsl,mpc5121-nfc", }, 8428c2ecf20Sopenharmony_ci {}, 8438c2ecf20Sopenharmony_ci}; 8448c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mpc5121_nfc_match); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic struct platform_driver mpc5121_nfc_driver = { 8478c2ecf20Sopenharmony_ci .probe = mpc5121_nfc_probe, 8488c2ecf20Sopenharmony_ci .remove = mpc5121_nfc_remove, 8498c2ecf20Sopenharmony_ci .driver = { 8508c2ecf20Sopenharmony_ci .name = DRV_NAME, 8518c2ecf20Sopenharmony_ci .of_match_table = mpc5121_nfc_match, 8528c2ecf20Sopenharmony_ci }, 8538c2ecf20Sopenharmony_ci}; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cimodule_platform_driver(mpc5121_nfc_driver); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ciMODULE_AUTHOR("Freescale Semiconductor, Inc."); 8588c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MPC5121 NAND MTD driver"); 8598c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 860