| /******************************************************************************* |
| Copyright (C) Marvell International Ltd. and its affiliates |
| |
| This software file (the "File") is owned and distributed by Marvell |
| International Ltd. and/or its affiliates ("Marvell") under the following |
| alternative licensing terms. Once you have made an election to distribute the |
| File under one of the following license alternatives, please (i) delete this |
| introductory statement regarding license alternatives, (ii) delete the two |
| license alternatives that you have not elected to use and (iii) preserve the |
| Marvell copyright notice above. |
| |
| ******************************************************************************** |
| Marvell Commercial License Option |
| |
| If you received this File from Marvell and you have entered into a commercial |
| license agreement (a "Commercial License") with Marvell, the File is licensed |
| to you under the terms of the applicable Commercial License. |
| |
| ******************************************************************************** |
| Marvell GPL License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File in accordance with the terms and conditions of the General |
| Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| available along with the File in the license.txt file or by writing to the Free |
| Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| |
| THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| DISCLAIMED. The GPL License provides additional details about this warranty |
| disclaimer. |
| ******************************************************************************** |
| Marvell BSD License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File under the following licensing terms. |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted provided that the following conditions are met: |
| |
| * Redistributions of source code must retain the above copyright notice, |
| this list of conditions and the following disclaimer. |
| |
| * Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| * Neither the name of Marvell nor the names of its contributors may be |
| used to endorse or promote products derived from this software without |
| specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| *******************************************************************************/ |
| |
| #include "mvCommon.h" |
| #include "mvOs.h" |
| #include "mvNfcRegs.h" |
| #ifdef MV_INCLUDE_PDMA |
| #include "pdma/mvPdma.h" |
| #include "pdma/mvPdmaRegs.h" |
| #endif |
| #include "mvNfc.h" |
| |
| #ifdef _DEBUG__ |
| #define DB(x) x |
| #else |
| #define DB(x) |
| #endif |
| /*************/ |
| /* Constants */ |
| /*************/ |
| |
| #define NFC_NATIVE_READ_ID_CMD 0x0090 |
| #define NFC_READ_ID_ADDR_LEN 1 |
| #define NFC_ERASE_ADDR_LEN 3 |
| #define NFC_SP_READ_ADDR_LEN 3 |
| #define NFC_SP_BIG_READ_ADDR_LEN 4 |
| #define NFC_LP_READ_ADDR_LEN 5 |
| #define NFC_BLOCK_ADDR_BITS 0xFFFFFF |
| #define NFC_SP_COL_OFFS 0 |
| #define NFC_SP_COL_MASK (0xFF << NFC_SP_COL_OFFS) |
| #define NFC_LP_COL_OFFS 0 |
| #define NFC_LP_COL_MASK (0xFFFF << NFC_SP_COL_OFFS) |
| #define NFC_SP_PG_OFFS 8 |
| #define NFC_SP_PG_MASK (0xFFFFFF << NFC_SP_PG_OFFS) |
| #define NFC_LP_PG_OFFS 16 |
| #define NFC_LP_PG_MASK (0xFFFF << NFC_LP_PG_OFFS) |
| #define NFC_PG_CNT_OFFS 8 |
| #define NFC_PG_CNT_MASK (0xFF << NFC_PG_CNT_OFFS) |
| |
| /* NAND special features bitmask definition. */ |
| #define NFC_FLAGS_NONE 0x0 |
| #define NFC_FLAGS_ONFI_MODE_3_SET 0x1 |
| #define NFC_CLOCK_UPSCALE_200M 0x2 |
| |
| /* End of NAND special features definitions. */ |
| |
| #define NFC_READ_ID_PDMA_DATA_LEN 32 |
| #define NFC_READ_STATUS_PDMA_DATA_LEN 32 |
| #define NFC_READ_ID_PIO_DATA_LEN 8 |
| #define NFC_READ_STATUS_PIO_DATA_LEN 8 |
| #define NFC_RW_SP_PDMA_DATA_LEN 544 |
| #define NFC_RW_SP_NO_ECC_DATA_LEN 528 |
| #define NFC_RW_SP_HMNG_ECC_DATA_LEN 520 |
| #define NFC_RW_SP_G_NO_ECC_DATA_LEN 528 |
| #define NFC_RW_SP_G_HMNG_ECC_DATA_LEN 526 |
| |
| #define NFC_RW_LP_PDMA_DATA_LEN 2112 |
| |
| #define NFC_RW_LP_NO_ECC_DATA_LEN 2112 |
| #define NFC_RW_LP_HMNG_ECC_DATA_LEN 2088 |
| #define NFC_RW_LP_BCH_ECC_DATA_LEN 2080 |
| |
| #define NFC_RW_LP_G_NO_ECC_DATA_LEN 2112 |
| #define NFC_RW_LP_G_HMNG_ECC_DATA_LEN 2088 |
| #define NFC_RW_LP_G_BCH_ECC_DATA_LEN 2080 |
| |
| #define NFC_RW_LP_BCH1K_ECC_DATA_LEN 1024 |
| #define NFC_RW_LP_BCH704B_ECC_DATA_LEN 704 |
| #define NFC_RW_LP_BCH512B_ECC_DATA_LEN 512 |
| |
| #define NFC_CMD_STRUCT_SIZE (sizeof(MV_NFC_CMD)) |
| #define NFC_CMD_BUFF_SIZE(cmdb_0) ((cmdb_0 & NFC_CB0_LEN_OVRD_MASK) ? 16 : 12) |
| #define NFC_CMD_BUFF_ADDR (NFC_COMMAND_BUFF_0_REG_4PDMA) |
| #define NFC_DATA_BUFF_ADDR (NFC_DATA_BUFF_REG_4PDMA) |
| |
| |
| #define TIMING_MAX_tADL 0x1f |
| #define TIMING_DEF_SEL_CNTR 0x1 |
| #define TIMING_MAX_RD_CNT_DEL 0x0 |
| #define TIMING_MAX_tCH 0x7 |
| #define TIMING_MAX_tCS 0x7 |
| #define TIMING_MAX_tWH 0x7 |
| #define TIMING_MAX_tWP 0x7 |
| #define TIMING_MAX_etRP 0x1 |
| #define TIMING_MAX_tRH 0x7 |
| #define TIMING_MAX_tRP 0x7 |
| |
| #define MV_NDTR0CS0_REG ((TIMING_MAX_tADL << 27) | \ |
| (TIMING_DEF_SEL_CNTR << 26) | \ |
| (TIMING_MAX_RD_CNT_DEL << 22) | \ |
| (TIMING_MAX_tCH << 19) | \ |
| (TIMING_MAX_tCS << 16) | \ |
| (TIMING_MAX_tWH << 11) | \ |
| (TIMING_MAX_tWP << 8) | \ |
| (TIMING_MAX_etRP << 6) | \ |
| (TIMING_MAX_tRH << 3) | \ |
| (TIMING_MAX_tRP)) |
| |
| #define TIMING_tR 0xff |
| #define TIMING_WAIT_MODE 0x1 /* Work with RnB signal (1) or ignore it (0) */ |
| #define TIMING_PRESCALE 0x0 /* no prescalling */ |
| #define TIMING_MAX_tRHW 0x0 |
| #define TIMING_MAX_tWHR 0xf |
| #define TIMING_MAX_tAR 0xf |
| |
| #define MV_NDTR1CS0_REG ((TIMING_tR << 16) | \ |
| (TIMING_WAIT_MODE << 15) | \ |
| (TIMING_PRESCALE << 14) | \ |
| (TIMING_MAX_tRHW << 8) | \ |
| (TIMING_MAX_tWHR << 4) | \ |
| (TIMING_MAX_tAR)) |
| |
| |
| /**********/ |
| /* Macros */ |
| /**********/ |
| #define ns_clk(ns, ns2clk) ((ns % ns2clk) ? (MV_U32)((ns/ns2clk)+1) : (MV_U32)(ns/ns2clk)) |
| #define maxx(a, b) ((a > b) ? a : b) |
| #define check_limit(val, pwr) ((val > ((1 << pwr)-1)) ? ((1 << pwr)-1) : val) |
| |
| #ifdef CONFIG_CPU_BIG_ENDIAN |
| #define MV_LE32_TO_CPU(x) le32_to_cpu(x) |
| #define MV_CPU_TO_LE32(x) cpu_to_le32(x) |
| #else |
| #define MV_LE32_TO_CPU(x) (x) |
| #define MV_CPU_TO_LE32(x) (x) |
| #endif |
| |
| #define DBGPRINT(x) printk(x) |
| #define DBGLVL KERN_INFO |
| |
| |
| |
| #ifndef MV_NAND_REG_BIT_SET |
| #define MV_NAND_REG_BIT_SET MV_REG_BIT_SET |
| #endif |
| #ifndef MV_NAND_REG_BIT_RESET |
| #define MV_NAND_REG_BIT_RESET MV_REG_BIT_RESET |
| #endif |
| |
| #ifndef MV_NAND_REG_WRITE |
| #define MV_NAND_REG_WRITE MV_REG_WRITE |
| #endif |
| |
| #ifndef MV_NAND_REG_READ |
| #define MV_NAND_REG_READ MV_REG_READ |
| #endif |
| |
| |
| /***********/ |
| /* Typedef */ |
| /***********/ |
| |
| /* Flash Timing Parameters */ |
| typedef struct { |
| /* Flash Timing */ |
| MV_U32 tADL; /* Address to write data delay */ |
| MV_U32 tCH; /* Enable signal hold time */ |
| MV_U32 tCS; /* Enable signal setup time */ |
| MV_U32 tWC; /* ND_nWS cycle duration */ |
| MV_U32 tWH; /* ND_nWE high duration */ |
| MV_U32 tWP; /* ND_nWE pulse time */ |
| MV_U32 tRC; /* ND_nRE cycle duration */ |
| MV_U32 tRH; /* ND_nRE high duration */ |
| MV_U32 tRP; /* ND_nRE pulse width */ |
| MV_U32 tR; /* ND_nWE high to ND_nRE low for read */ |
| MV_U32 tWHR; /* ND_nWE high to ND_nRE low for status read */ |
| MV_U32 tAR; /* ND_ALE low to ND_nRE low delay */ |
| MV_U32 tRHW; /* ND_nRE high to ND_nWE low delay */ |
| /* Physical Layout */ |
| MV_U32 pgPrBlk; /* Pages per block */ |
| MV_U32 pgSz; /* Page size */ |
| MV_U32 oobSz; /* Page size */ |
| MV_U32 blkNum; /* Number of blocks per device */ |
| MV_U32 id; /* Manufacturer and device IDs */ |
| MV_U32 seqDis; /* Enable/Disable sequential multipage read */ |
| MV_8 *model; /* Flash Model string */ |
| MV_U32 bb_page; /* Page containing bad block marking */ |
| MV_U32 flags; /* Special features configuration. */ |
| } MV_NFC_FLASH_INFO; |
| |
| /* Flash command set */ |
| typedef struct { |
| MV_U16 read1; |
| MV_U16 exitCacheRead; |
| MV_U16 cacheReadRand; |
| MV_U16 cacheReadSeq; |
| MV_U16 read2; |
| MV_U16 program; |
| MV_U16 readStatus; |
| MV_U16 readId; |
| MV_U16 erase; |
| MV_U16 multiplaneErase; |
| MV_U16 reset; |
| MV_U16 lock; |
| MV_U16 unlock; |
| MV_U16 lockStatus; |
| } MV_NFC_FLASH_CMD_SET; |
| |
| /* ONFI Mode type */ |
| typedef enum { |
| MV_NFC_ONFI_MODE_0, |
| MV_NFC_ONFI_MODE_1, |
| MV_NFC_ONFI_MODE_2, |
| MV_NFC_ONFI_MODE_3, |
| MV_NFC_ONFI_MODE_4, |
| MV_NFC_ONFI_MODE_5 |
| } MV_NFC_ONFI_MODE; |
| |
| /********/ |
| /* Data */ |
| /********/ |
| |
| /* Defined Flash Types */ |
| MV_NFC_FLASH_INFO flashDeviceInfo[] = { |
| { /* Micron 4Gb */ |
| .tADL = 70, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 15, /* tCS, Enable signal setup time */ |
| .tWC = 20, /* tWC, ND_nWE cycle duration */ |
| .tWH = 7, /* tWH, ND_nWE high duration */ |
| .tWP = 10, /* tWP, ND_nWE pulse time */ |
| .tRC = 20, /* tWC, ND_nRE cycle duration */ |
| .tRH = 7, /* tRH, ND_nRE high duration */ |
| .tRP = 10, /* tRP, ND_nRE pulse width */ |
| .tR = 25000, /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read - 25000+20+100+1 */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 100, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 2048, /* Page size */ |
| .oobSz = 64, /* Spare size */ |
| .blkNum = 4096, /* Number of blocks/sectors in the flash */ |
| .id = 0xDC2C, /* Device ID 0xDevice,Vendor */ |
| .model = "Micron 4Gb 8bit", |
| .bb_page = 63, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| |
| { /* ST 1Gb */ |
| .tADL = 100, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 20, /* tCS, Enable signal setup time */ |
| .tWC = 30, /* tWC, ND_nWE cycle duration */ |
| .tWH = 10, /* tWH, ND_nWE high duration */ |
| .tWP = 15, /* tWP, ND_nWE pulse time */ |
| .tRC = 25, /* tWC, ND_nRE cycle duration */ |
| .tRH = 10, /* tRH, ND_nRE high duration */ |
| .tRP = 15, /* tRP, ND_nRE pulse width */ |
| .tR = 25000, /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read - 25000+20+100+1 */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 30, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 2048, /* Page size */ |
| .oobSz = 64, /* Spare size */ |
| .blkNum = 1024, /* Number of blocks/sectors in the flash */ |
| .id = 0xF120, /* Device ID 0xDevice,Vendor */ |
| .model = "ST 1Gb 8bit", |
| .bb_page = 63, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| |
| { /* ST 8Gb */ |
| .tADL = 0, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 20, /* tCS, Enable signal setup time */ |
| .tWC = 24, /* tWC, ND_nWE cycle duration */ |
| .tWH = 12, /* tWH, ND_nWE high duration */ |
| .tWP = 12, /* tWP, ND_nWE pulse time */ |
| .tRC = 24, /* tWC, ND_nRE cycle duration */ |
| .tRH = 12, /* tRH, ND_nRE high duration */ |
| .tRP = 12, /* tRP, ND_nRE pulse width */ |
| .tR = 25121, /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read - 25000+20+100+1 */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 48, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 2048, /* Page size */ |
| .oobSz = 64, /* Spare size */ |
| .blkNum = 2048, /* Number of blocks/sectors in the flash */ |
| .id = 0xD320, /* Device ID 0xDevice,Vendor */ |
| .model = "ST 8Gb 8bit", |
| .bb_page = 63, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| { /* ST 4Gb */ |
| .tADL = 70, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 20, /* tCS, Enable signal setup time */ |
| .tWC = 22, /* tWC, ND_nWE cycle duration */ |
| .tWH = 10, /* tWH, ND_nWE high duration */ |
| .tWP = 12, /* tWP, ND_nWE pulse time */ |
| .tRC = 24, /* tWC, ND_nRE cycle duration */ |
| .tRH = 12, /* tRH, ND_nRE high duration */ |
| .tRP = 12, /* tRP, ND_nRE pulse width */ |
| .tR = 25121, /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read - 25000+20+100+1 */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 100, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 2048, /* Page size */ |
| .oobSz = 64, /* Spare size */ |
| .blkNum = 2048, /* Number of blocks/sectors in the flash */ |
| .id = 0xDC20, /* Device ID 0xDevice,Vendor */ |
| .model = "NM 4Gb 8bit", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| { /* ST 32Gb */ |
| .tADL = 0, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 20, /* tCS, Enable signal setup time */ |
| .tWC = 22, /* tWC, ND_nWE cycle duration */ |
| .tWH = 10, /* tWH, ND_nWE high duration */ |
| .tWP = 12, /* tWP, ND_nWE pulse time */ |
| .tRC = 22, /* tWC, ND_nRE cycle duration */ |
| .tRH = 10, /* tRH, ND_nRE high duration */ |
| .tRP = 12, /* tRP, ND_nRE pulse width */ |
| .tR = 25121, /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read - 25000+20+100+1 */ |
| .tWHR = 80, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 48, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 4096, /* Page size */ |
| .oobSz = 128, /* Spare size */ |
| .blkNum = 16384, /* Number of blocks/sectors in the flash */ |
| .id = 0xD520, /* Device ID 0xVendor,device */ |
| .model = "ST 32Gb 8bit", |
| .bb_page = 63, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| |
| { /* Samsung 16Gb */ |
| .tADL = 90, /* tADL, Address to write data delay */ |
| .tCH = 0, /* tCH, Enable signal hold time */ |
| .tCS = 5, /* tCS, Enable signal setup time */ |
| .tWC = 22, /* tWC, ND_nWE cycle duration */ |
| .tWH = 10, /* tWH, ND_nWE high duration */ |
| .tWP = 12, /* tWP, ND_nWE pulse time */ |
| .tRC = 24, /* tWC, ND_nRE cycle duration */ |
| .tRH = 12, /* tRH, ND_nRE high duration */ |
| .tRP = 12, /* tRP, ND_nRE pulse width */ |
| .tR = 49146, /* tR = data transfer from cell to register, maximum 60,000ns */ |
| .tWHR = 66, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 66, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 32, /* tRHW, ND_nRE high to ND_nWE low delay 32 clocks */ |
| .pgPrBlk = 128, /* Pages per block - detected */ |
| .pgSz = 2048, /* Page size */ |
| .oobSz = 64, /* Spare size */ |
| .blkNum = 8192, /* Number of blocks/sectors in the flash */ |
| .id = 0xD5EC, /* Device ID 0xDevice,Vendor */ |
| .model = "Samsung 16Gb 8bit", |
| .bb_page = 127, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| |
| { /* Samsung 2Gb */ |
| .tADL = 90, /* tADL, Address to write data delay */ |
| .tCH = 10, /* tCH, Enable signal hold time */ |
| .tCS = 0, /* tCS, Enable signal setup time */ |
| .tWC = 40, /* tWC, ND_nWE cycle duration */ |
| .tWH = 15, /* tWH, ND_nWE high duration */ |
| .tWP = 25, /* tWP, ND_nWE pulse time */ |
| .tRC = 40, /* tWC, ND_nRE cycle duration */ |
| .tRH = 15, /* tRH, ND_nRE high duration */ |
| .tRP = 25, /* tRP, ND_nRE pulse width */ |
| .tR = 25000, /* tR = data transfer from cell to register, maximum 60,000ns */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 30, /* tRHW, ND_nRE high to ND_nWE low delay 32 clocks */ |
| .pgPrBlk = 128, /* Pages per block - detected */ |
| .pgSz = 2048, /* Page size */ |
| .oobSz = 64, /* Spare size */ |
| .blkNum = 1024, /* Number of blocks/sectors in the flash */ |
| .id = 0xDAEC, /* Device ID 0xDevice,Vendor */ /* 0x9AA8 when run through JTAG */ |
| .model = "Samsung 2Gb 8bit", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| |
| { /* Samsung 8Gb */ |
| .tADL = 100, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 20, /* tCS, Enable signal setup time */ |
| .tWC = 22, /* tWC, ND_nWE cycle duration */ |
| .tWH = 10, /* tWH, ND_nWE high duration */ |
| .tWP = 12, /* tWP, ND_nWE pulse time */ |
| .tRC = 22, /* tWC, ND_nRE cycle duration */ |
| .tRH = 10, /* tRH, ND_nRE high duration */ |
| .tRP = 12, /* tRP, ND_nRE pulse width */ |
| .tR = 25000, /* tR = data transfer from cell to register, maximum 60,000ns */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 100, /* tRHW, ND_nRE high to ND_nWE low delay 32 clocks */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 4096, /* Page size */ |
| .oobSz = 128, /* Spare size */ |
| .blkNum = 4096, /* Number of blocks/sectors in the flash */ |
| .id = 0xD3EC, /* Device ID 0xDevice,Vendor */ /* 0x9AA8 when run through JTAG */ |
| .model = "Samsung 8Gb 8bit", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| |
| { /* Samsung 4Gb */ |
| .tADL = 70, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 20, /* tCS, Enable signal setup time */ |
| .tWC = 22, /* tWC, ND_nWE cycle duration */ |
| .tWH = 10, /* tWH, ND_nWE high duration */ |
| .tWP = 12, /* tWP, ND_nWE pulse time */ |
| .tRC = 22, /* tWC, ND_nRE cycle duration */ |
| .tRH = 10, /* tRH, ND_nRE high duration */ |
| .tRP = 12, /* tRP, ND_nRE pulse width */ |
| .tR = 25000, /* tR = data transfer from cell to register, maximum 60,000ns */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 100, /* tRHW, ND_nRE high to ND_nWE low delay 32 clocks */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 2048, /* Page size */ |
| .oobSz = 64, /* Spare size */ |
| .blkNum = 2048, /* Number of blocks/sectors in the flash */ |
| .id = 0xDCEC, /* Device ID 0xDevice,Vendor */ /* 0x9AA8 when run through JTAG */ |
| .model = "Samsung 4Gb 8bit", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| |
| { /* Samsung 32Gb */ |
| .tADL = 0, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 20, /* tCS, Enable signal setup time */ |
| .tWC = 25, /* tWC, ND_nWE cycle duration */ |
| .tWH = 10, /* tWH, ND_nWE high duration */ |
| .tWP = 15, /* tWP, ND_nWE pulse time */ |
| .tRC = 30, /* tWC, ND_nRE cycle duration */ |
| .tRH = 15, /* tRH, ND_nRE high duration */ |
| .tRP = 15, /* tRP, ND_nRE pulse width */ |
| .tR = 60000, /* tR = data transfer from cell to register, maximum 60,000ns */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 48, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 128, /* Pages per block - detected */ |
| .pgSz = 4096, /* Page size */ |
| .oobSz = 128, /* Spare size */ |
| .blkNum = 8192, /* Number of blocks/sectors in the flash */ |
| .id = 0xD7EC, /* Device ID 0xDevice,Vendor */ |
| .model = "Samsung 32Gb 8bit", |
| .bb_page = 127, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| { /* Micron 32Gb */ |
| .tADL = 200, /* tADL, Address to write data delay */ |
| .tCH = 20, /* tCH, Enable signal hold time */ |
| .tCS = 70, /* tCS, Enable signal setup time */ |
| .tWC = 100, /* tWC, ND_nWE cycle duration */ |
| .tWH = 30, /* tWH, ND_nWE high duration */ |
| .tWP = 50, /* tWP, ND_nWE pulse time */ |
| .tRC = 100, /* tWC, ND_nRE cycle duration */ |
| .tRH = 45, /* tRH, ND_nRE high duration */ |
| .tRP = 50, /* tRP, ND_nRE pulse width */ |
| .tR = 35000, /* tR = data transfer from cell to register */ |
| .tWHR = 120, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 25, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 200, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 128, /* Pages per block - detected */ |
| .pgSz = 8192, /* Page size */ |
| .oobSz = 160, /* Spare size */ |
| .blkNum = 4096, /* Number of blocks/sectors in the flash */ |
| .id = 0x682C, /* Device ID 0xDevice,Vendor */ |
| .model = "Micron 32Gb 8bit", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| { /* Micron 64Gb */ |
| .tADL = 0, /* tADL, Address to write data delay */ |
| .tCH = 20, /* tCH, Enable signal hold time */ |
| .tCS = 20, /* tCS, Enable signal setup time */ |
| .tWC = 90, /* tWC, ND_nWE cycle duration */ |
| .tWH = 45, /* tWH, ND_nWE high duration */ |
| .tWP = 45, /* tWP, ND_nWE pulse time */ |
| .tRC = 90, /* tWC, ND_nRE cycle duration */ |
| .tRH = 45, /* tRH, ND_nRE high duration */ |
| .tRP = 45, /* tRP, ND_nRE pulse width */ |
| .tR = 0, /* tR = data transfer from cell to register */ |
| .tWHR = 90, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 65, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 32, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 256, /* Pages per block - detected */ |
| .pgSz = 8192, /* Page size */ |
| .oobSz = 448, /* Spare size */ |
| .blkNum = 4096, /* Number of blocks/sectors in the flash */ |
| .id = 0x882C, /* Device ID 0xDevice,Vendor */ |
| .model = "Micron 64Gb 8bit", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| { /* Hinyx 8Gb */ |
| .tADL = 0, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 20, /* tCS, Enable signal setup time */ |
| .tWC = 22, /* tWC, ND_nWE cycle duration */ |
| .tWH = 10, /* tWH, ND_nWE high duration */ |
| .tWP = 12, /* tWP, ND_nWE pulse time */ |
| .tRC = 22, /* tWC, ND_nRE cycle duration */ |
| .tRH = 10, /* tRH, ND_nRE high duration */ |
| .tRP = 12, /* tRP, ND_nRE pulse width */ |
| .tR = 25, /* tR = data transfer from cell to register */ |
| .tWHR = 80, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 100, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 2048, /* Page size */ |
| .oobSz = 64, /* Spare size */ |
| .blkNum = 8192, /* Number of blocks/sectors in the flash */ |
| .id = 0xDCAD, /* Device ID 0xDevice,Vendor */ |
| .model = "Hynix 8Gb 8bit", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| }, |
| /* Timing used is ONFI Mode 2 (28Mhz) */ |
| { /* Micron 8Gb */ |
| .tADL = 100, /* tADL, Address to write data delay */ |
| .tCH = 10, /* tCH, Enable signal hold time */ |
| .tCS = 25, /* tCS, Enable signal setup time */ |
| .tWC = 35, /* tWC, ND_nWE cycle duration */ |
| .tWH = 17, /* tWH, ND_nWE high duration */ |
| .tWP = 20, /* tWP, ND_nWE pulse time */ |
| .tRC = 35, /* tWC, ND_nRE cycle duration */ |
| .tRH = 17, /* tRH, ND_nRE high duration */ |
| .tRP = 17, /* tRP, ND_nRE pulse width */ |
| .tR = 25241, /* tR = data transfer from cell to register tR = tR+tRR+tWB+1 */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 100, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 128, /* Pages per block - detected */ |
| .pgSz = 4096, /* Page size */ |
| .oobSz = 224, /* Spare size */ |
| .blkNum = 2048, /* Number of blocks/sectors in the flash */ |
| .id = 0x382C, /* Device ID 0xDevice,Vendor */ |
| .model = "Micron 8Gb 8bit ABABA", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = (NFC_CLOCK_UPSCALE_200M | NFC_FLAGS_ONFI_MODE_3_SET) |
| }, |
| { /* Micron 256MB */ |
| .tADL = 100, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 25, /* tCS, Enable signal setup time */ |
| .tWC = 30, /* tWC, ND_nWE cycle duration */ |
| .tWH = 15, /* tWH, ND_nWE high duration */ |
| .tWP = 15, /* tWP, ND_nWE pulse time */ |
| .tRC = 30, /* tWC, ND_nRE cycle duration */ |
| .tRH = 10, /* tRH, ND_nRE high duration */ |
| .tRP = 15, /* tRP, ND_nRE pulse width */ |
| .tR = 25241, /* tR = data transfer from cell to register tR = tR+tRR+tWB+1 */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 100, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 2048, /* Page size */ |
| .oobSz = 224, /* Spare size */ |
| .blkNum = 2048, /* Number of blocks/sectors in the flash */ |
| .id = 0xda2C, /* Device ID 0xDevice,Vendor */ |
| .model = "Micron 256MB", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = (NFC_CLOCK_UPSCALE_200M | NFC_FLAGS_ONFI_MODE_3_SET) |
| }, |
| { /* Micron 8Gb ABACA */ |
| /* timing Asynchronous mode 3 */ |
| .tADL = 100, /* tADL, Address to write data delay */ |
| .tCH = 10, /* tCH, Enable signal hold time */ |
| .tCS = 25, /* tCS, Enable signal setup time */ |
| .tWC = 35, /* tWC, ND_nWE cycle duration, limited to 35 by the ARMADA-XP CPU */ |
| .tWH = 17, /* tWH, ND_nWE high duration */ |
| .tWP = 15, /* tWP, ND_nWE pulse time */ |
| .tRC = 35, /* tRC, ND_nRE cycle duration, limited to 35 by the ARMADA-XP CPU */ |
| .tRH = 17, /* tRH, ND_nRE high duration */ |
| .tRP = 15, /* tRP, ND_nRE pulse width */ |
| .tR = 25241, /* tR = data transfer from cell to register tR = tR+tRR+tWB+1 */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 100, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 4096, /* Page size */ |
| .oobSz = 224, /* Spare size */ |
| .blkNum = 4096, /* Number of blocks/sectors in the flash */ |
| .id = 0xd32C, /* Device ID 0xDevice,Vendor */ |
| .model = "Micron 8Gb 8bit ABACA", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = (NFC_CLOCK_UPSCALE_200M) |
| }, |
| { /* Micron 2Gb ABAFA */ |
| /* 3.3v parametrs */ |
| .tADL = 70, /* tADL, Address to write data delay */ |
| .tCH = 5, /* tCH, Enable signal hold time */ |
| .tCS = 15, /* tCS, Enable signal setup time */ |
| .tWC = 20, /* tWC, ND_nWE cycle duration, limited to 35 by the ARMADA-XP CPU */ |
| .tWH = 7, /* tWH, ND_nWE high duration */ |
| .tWP = 10, /* tWP, ND_nWE pulse time */ |
| .tRC = 21, /* tRC, ND_nRE cycle duration, limited to 35 by the ARMADA-XP CPU */ |
| .tRH = 7, /* tRH, ND_nRE high duration */ |
| .tRP = 10, /* tRP, ND_nRE pulse width */ |
| .tR = 25121, /* tR = data transfer from cell to register tR = tR+tRR+tWB+1 */ |
| .tWHR = 60, /* tWHR, ND_nWE high to ND_nRE low delay for status read */ |
| .tAR = 10, /* tAR, ND_ALE low to ND_nRE low delay */ |
| .tRHW = 100, /* tRHW, ND_nRE high to ND_nWE low delay */ |
| .pgPrBlk = 64, /* Pages per block - detected */ |
| .pgSz = 2048, /* Page size */ |
| .oobSz = 224, /* Spare size */ |
| .blkNum = 2048, /* Number of blocks/sectors in the flash */ |
| .id = 0xDA2C, /* Device ID 0xDevice,Vendor */ |
| .model = "Micron 2Gb 8bit ABAFA", |
| .bb_page = 0, /* Manufacturer Bad block marking page in block */ |
| .flags = NFC_CLOCK_UPSCALE_200M |
| } |
| }; |
| |
| /* Defined Command set */ |
| #define MV_NFC_FLASH_SP_CMD_SET_IDX 0 |
| #define MV_NFC_FLASH_LP_CMD_SET_IDX 1 |
| static MV_NFC_FLASH_CMD_SET flashCmdSet[] = { |
| { |
| .read1 = 0x0000, |
| .read2 = 0x0050, |
| .program = 0x1080, |
| .readStatus = 0x0070, |
| .readId = 0x0090, |
| .erase = 0xD060, |
| .multiplaneErase = 0xD160, |
| .reset = 0x00FF, |
| .lock = 0x002A, |
| .unlock = 0x2423, |
| .lockStatus = 0x007A, |
| }, |
| { |
| .read1 = 0x3000, |
| .exitCacheRead = 0x003f, |
| .cacheReadRand = 0x3100, |
| .cacheReadSeq = 0x0031, |
| .read2 = 0x0050, |
| .program = 0x1080, |
| .readStatus = 0x0070, |
| .readId = 0x0090, |
| .erase = 0xD060, |
| .multiplaneErase = 0xD160, |
| .reset = 0x00FF, |
| .lock = 0x002A, |
| .unlock = 0x2423, |
| .lockStatus = 0x007A, |
| } |
| }; |
| |
| /*#define MV_NFC_REG_DBG*/ |
| #ifdef MV_NFC_REG_DBG |
| MV_U32 mvNfcDbgFlag = 1; |
| |
| MV_U32 nfc_dbg_read(MV_U32 addr) |
| { |
| MV_U32 reg = MV_MEMIO_LE32_READ((INTER_REGS_BASE | addr)); |
| if (mvNfcDbgFlag) |
| mvOsPrintf("NFC read 0x%08x = %08x\n", addr, reg); |
| return reg; |
| } |
| |
| MV_VOID nfc_dbg_write(MV_U32 addr, MV_U32 val) |
| { |
| MV_MEMIO_LE32_WRITE((INTER_REGS_BASE | addr), (val)); |
| |
| if (mvNfcDbgFlag) |
| mvOsPrintf("NFC write 0x%08x = %08x\n", addr, val); |
| } |
| |
| #undef MV_NAND_REG_READ |
| #undef MV_NAND_REG_WRITE |
| #define MV_NAND_REG_READ(x) nfc_dbg_read(x) |
| #define MV_NAND_REG_WRITE(x, y) nfc_dbg_write(x, y) |
| #endif |
| |
| /**************/ |
| /* Prototypes */ |
| /**************/ |
| static MV_STATUS mvDfcWait4Complete(MV_U32 statMask, MV_U32 usec); |
| static MV_STATUS mvNfcReadIdNative(MV_NFC_CHIP_SEL cs, MV_U16 *id); |
| static MV_STATUS mvNfcTimingSet(MV_U32 nand_clock, MV_NFC_FLASH_INFO *flInfo); |
| static MV_U32 mvNfcColBits(MV_U32 pg_size); |
| static MV_STATUS mvNfcDeviceFeatureSet(MV_NFC_CTRL *nfcCtrl, MV_U8 cmd, MV_U8 addr, MV_U32 data0, MV_U32 data1); |
| static MV_STATUS mvNfcDeviceFeatureGet(MV_NFC_CTRL *nfcCtrl, MV_U8 cmd, MV_U8 addr, MV_U32 *data0, MV_U32 *data1); |
| static MV_STATUS mvNfcDeviceModeSet(MV_NFC_CTRL *nfcCtrl, MV_NFC_ONFI_MODE mode); |
| static MV_STATUS mvNfcReadParamPage(struct parameter_page_t *ppage); |
| |
| /**************/ |
| /* Local Data */ |
| /**************/ |
| struct parameter_page_t paramPage; |
| |
| /******************************************************************************* |
| * mvNfcInit |
| * |
| * DESCRIPTION: |
| * Initialize the NAND controller unit, and perform a detection of the |
| * attached NAND device. |
| * |
| * INPUT: |
| * nfcInfo - Flash information parameters. |
| * |
| * OUTPUT: |
| * nfcCtrl - Nand control and status information to be held by the user |
| * and passed to all other APIs. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_BAD_PARAM - The required ECC mode not supported by flash. |
| * MV_NOT_SUPPORTED- The underlying flash device is not supported by HAL. |
| * MV_TIMEOUT - Error accessing the underlying flahs device. |
| * MV_FAIL - On failure |
| *******************************************************************************/ |
| MV_STATUS mvNfcInit(MV_NFC_INFO *nfcInfo, MV_NFC_CTRL *nfcCtrl, struct MV_NFC_HAL_DATA *halData) |
| { |
| MV_U32 ctrl_reg; |
| MV_STATUS ret; |
| MV_U16 read_id = 0; |
| MV_U32 i; |
| MV_U32 nand_clock; |
| /* Initial register values */ |
| ctrl_reg = 0; |
| /* |
| Reduce NAND clock for supporting slower flashes for initialization |
| ECC engine clock = (2Ghz / divider) |
| NFC clock = ECC clock / 2 |
| */ |
| nand_clock = halData->mvCtrlNandClkSetFunction(_100MHz); /* Go down to 100MHz */ |
| if (nand_clock != _100MHz) |
| DB(mvOsPrintf("%s: Warning: set NFC Clock frequency to %dHz instead of %dHz\n", |
| __func__, nand_clock, _100MHz)); |
| |
| DB(mvOsPrintf("mvNfcInit: set nand clock to %d\n", nand_clock)); |
| |
| /* Relax Timing configurations to avoid timing violations after flash reset */ |
| MV_NAND_REG_WRITE(NFC_TIMING_0_REG, MV_NDTR0CS0_REG); |
| MV_NAND_REG_WRITE(NFC_TIMING_1_REG, MV_NDTR1CS0_REG); |
| |
| /* make sure ECC is disabled at this point - will be enabled only when issuing certain commands */ |
| MV_NAND_REG_BIT_RESET(NFC_CONTROL_REG, NFC_CTRL_ECC_EN_MASK); |
| if (nfcInfo->eccMode != MV_NFC_ECC_HAMMING) |
| MV_NAND_REG_BIT_RESET(NFC_ECC_CONTROL_REG, NFC_ECC_BCH_EN_MASK); |
| |
| if ((nfcInfo->eccMode == MV_NFC_ECC_BCH_1K) || |
| (nfcInfo->eccMode == MV_NFC_ECC_BCH_704B) || (nfcInfo->eccMode == MV_NFC_ECC_BCH_512B)) |
| /* Disable spare */ |
| ctrl_reg &= ~NFC_CTRL_SPARE_EN_MASK; |
| else |
| /* Enable spare */ |
| ctrl_reg |= NFC_CTRL_SPARE_EN_MASK; |
| |
| ctrl_reg &= ~NFC_CTRL_ECC_EN_MASK; |
| |
| /* Configure flash interface */ |
| if (nfcInfo->ifMode == MV_NFC_IF_1X16) { |
| nfcCtrl->flashWidth = 16; |
| nfcCtrl->dfcWidth = 16; |
| ctrl_reg |= (NFC_CTRL_DWIDTH_M_MASK | NFC_CTRL_DWIDTH_C_MASK); |
| } else if (nfcInfo->ifMode == MV_NFC_IF_2X8) { |
| nfcCtrl->flashWidth = 8; |
| nfcCtrl->dfcWidth = 16; |
| ctrl_reg |= NFC_CTRL_DWIDTH_C_MASK; |
| } else { |
| nfcCtrl->flashWidth = 8; |
| nfcCtrl->dfcWidth = 8; |
| } |
| |
| /* Configure initial READ-ID byte count */ |
| ctrl_reg |= (0x2 << NFC_CTRL_RD_ID_CNT_OFFS); |
| |
| /* Configure the Arbiter */ |
| ctrl_reg |= NFC_CTRL_ND_ARB_EN_MASK; |
| |
| /* Write registers before device detection */ |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, ctrl_reg); |
| |
| #ifdef MTD_NAND_NFC_INIT_RESET |
| /* reset the device */ |
| ret = mvNfcReset(); |
| if (ret != MV_OK) |
| return ret; |
| #endif |
| |
| /* Read the device ID */ |
| ret = mvNfcReadIdNative(nfcCtrl->currCs, &read_id); |
| if (ret != MV_OK) |
| return ret; |
| |
| /* Look for device ID in knwon device table */ |
| for (i = 0; i < (sizeof(flashDeviceInfo) / sizeof(MV_NFC_FLASH_INFO)); i++) { |
| if (flashDeviceInfo[i].id == read_id) |
| break; |
| } |
| if (i == (sizeof(flashDeviceInfo) / sizeof(MV_NFC_FLASH_INFO))) |
| return MV_NOT_SUPPORTED; |
| else |
| nfcCtrl->flashIdx = i; |
| |
| /* In case of ONFI Mode set needed */ |
| if (flashDeviceInfo[i].flags & NFC_FLAGS_ONFI_MODE_3_SET) { |
| ret = mvNfcDeviceModeSet(nfcCtrl, MV_NFC_ONFI_MODE_3); |
| if (ret != MV_OK) |
| return ret; |
| if (MV_OK == mvNfcReadParamPage(¶mPage)) { |
| DB(mvNfcPrintParamPage()); |
| switch (paramPage.num_ECC_bits) { |
| case 1: |
| nfcInfo->eccMode = MV_NFC_ECC_HAMMING; |
| break; |
| case 4: |
| nfcInfo->eccMode = MV_NFC_ECC_BCH_2K; |
| break; |
| case 8: |
| nfcInfo->eccMode = MV_NFC_ECC_BCH_1K; |
| break; |
| case 24: |
| case 12: |
| nfcInfo->eccMode = MV_NFC_ECC_BCH_704B; |
| break; |
| case 16: |
| nfcInfo->eccMode = MV_NFC_ECC_BCH_512B; |
| break; |
| default: |
| nfcInfo->eccMode = MV_NFC_ECC_DISABLE; |
| break; |
| } |
| } else |
| mvOsPrintf("mvNfcReadParamPage (EC comand) return error\n"); |
| } |
| |
| /* Critical Initialization done. Raise NFC clock if needed */ |
| if (flashDeviceInfo[i].flags & NFC_CLOCK_UPSCALE_200M) { |
| nand_clock = halData->mvCtrlNandClkSetFunction(_200MHz); /* raise NFC clk to 200MHz */ |
| if (nand_clock != _200MHz) |
| DB(mvOsPrintf("%s: Warning: set NFC Clock frequency to %dHz instead of %dHz\n", |
| __func__, nand_clock, _200MHz)); |
| } |
| |
| DB(mvOsPrintf("mvNfcInit: set nand clock to %d\n", nand_clock)); |
| |
| /* Configure the command set based on page size */ |
| if (flashDeviceInfo[i].pgSz < MV_NFC_2KB_PAGE) |
| nfcCtrl->cmdsetIdx = MV_NFC_FLASH_SP_CMD_SET_IDX; |
| else |
| nfcCtrl->cmdsetIdx = MV_NFC_FLASH_LP_CMD_SET_IDX; |
| |
| /* calculate Timing parameters */ |
| ret = mvNfcTimingSet(nand_clock, &flashDeviceInfo[i]); |
| if (ret != MV_OK) { |
| DB(mvOsPrintf("mvNfcInit: mvNfcTimingSet failed for clock %d\n", nand_clock)); |
| return ret; |
| } |
| |
| /* Configure the control register based on the device detected */ |
| ctrl_reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| |
| /* Configure DMA */ |
| if (nfcInfo->ioMode == MV_NFC_PDMA_ACCESS) |
| ctrl_reg |= NFC_CTRL_DMA_EN_MASK; |
| else |
| ctrl_reg &= ~NFC_CTRL_DMA_EN_MASK; |
| |
| /* Configure Page size */ |
| ctrl_reg &= ~NFC_CTRL_PAGE_SZ_MASK; |
| switch (flashDeviceInfo[i].pgSz) { |
| case MV_NFC_512B_PAGE: |
| ctrl_reg |= NFC_CTRL_PAGE_SZ_512B; |
| break; |
| |
| case MV_NFC_2KB_PAGE: |
| case MV_NFC_4KB_PAGE: |
| case MV_NFC_8KB_PAGE: |
| ctrl_reg |= NFC_CTRL_PAGE_SZ_2KB; |
| break; |
| |
| default: |
| return MV_BAD_PARAM; |
| } |
| |
| /* Disable sequential read if indicated */ |
| if (flashDeviceInfo[i].seqDis) |
| ctrl_reg |= NFC_CTRL_SEQ_DIS_MASK; |
| else |
| ctrl_reg &= ~NFC_CTRL_SEQ_DIS_MASK; |
| |
| /* Configure the READ-ID count and row address start based on page size */ |
| ctrl_reg &= ~(NFC_CTRL_RD_ID_CNT_MASK | NFC_CTRL_RA_START_MASK); |
| if (flashDeviceInfo[i].pgSz >= MV_NFC_2KB_PAGE) { |
| ctrl_reg |= NFC_CTRL_RD_ID_CNT_LP; |
| ctrl_reg |= NFC_CTRL_RA_START_MASK; |
| } else { |
| ctrl_reg |= NFC_CTRL_RD_ID_CNT_SP; |
| } |
| |
| /* Confiugre pages per block */ |
| ctrl_reg &= ~NFC_CTRL_PG_PER_BLK_MASK; |
| switch (flashDeviceInfo[i].pgPrBlk) { |
| case 32: |
| ctrl_reg |= NFC_CTRL_PG_PER_BLK_32; |
| break; |
| |
| case 64: |
| ctrl_reg |= NFC_CTRL_PG_PER_BLK_64; |
| break; |
| |
| case 128: |
| ctrl_reg |= NFC_CTRL_PG_PER_BLK_128; |
| break; |
| |
| case 256: |
| ctrl_reg |= NFC_CTRL_PG_PER_BLK_256; |
| break; |
| |
| default: |
| return MV_BAD_PARAM; |
| } |
| |
| /* Write the updated control register */ |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, ctrl_reg); |
| |
| #ifdef MV_INCLUDE_PDMA |
| /* DMA resource allocation */ |
| if (nfcInfo->ioMode == MV_NFC_PDMA_ACCESS) { |
| /* Allocate command buffer */ |
| nfcCtrl->cmdBuff.bufVirtPtr = |
| mvOsIoUncachedMalloc(nfcInfo->osHandle, (NFC_CMD_STRUCT_SIZE * MV_NFC_MAX_DESC_CHAIN), |
| &nfcCtrl->cmdBuff.bufPhysAddr, &nfcCtrl->cmdBuff.memHandle); |
| if (nfcCtrl->cmdBuff.bufVirtPtr == NULL) |
| return MV_OUT_OF_CPU_MEM; |
| nfcCtrl->cmdBuff.bufSize = (NFC_CMD_STRUCT_SIZE * MV_NFC_MAX_DESC_CHAIN); |
| nfcCtrl->cmdBuff.dataSize = (NFC_CMD_STRUCT_SIZE * MV_NFC_MAX_DESC_CHAIN); |
| |
| /* Allocate command DMA descriptors */ |
| nfcCtrl->cmdDescBuff.bufVirtPtr = |
| mvOsIoUncachedMalloc(nfcInfo->osHandle, (MV_PDMA_DESC_SIZE * (MV_NFC_MAX_DESC_CHAIN + 1)), |
| &nfcCtrl->cmdDescBuff.bufPhysAddr, &nfcCtrl->cmdDescBuff.memHandle); |
| if (nfcCtrl->cmdDescBuff.bufVirtPtr == NULL) |
| return MV_OUT_OF_CPU_MEM; |
| /* verify allignment to 128bits */ |
| if ((MV_U32) nfcCtrl->cmdDescBuff.bufVirtPtr & 0xF) { |
| nfcCtrl->cmdDescBuff.bufVirtPtr = |
| (MV_U8 *) (((MV_U32) nfcCtrl->cmdDescBuff.bufVirtPtr & ~0xF) + MV_PDMA_DESC_SIZE); |
| nfcCtrl->cmdDescBuff.bufPhysAddr = |
| ((nfcCtrl->cmdDescBuff.bufPhysAddr & ~0xF) + MV_PDMA_DESC_SIZE); |
| } |
| nfcCtrl->cmdDescBuff.bufSize = (MV_PDMA_DESC_SIZE * MV_NFC_MAX_DESC_CHAIN); |
| nfcCtrl->cmdDescBuff.dataSize = (MV_PDMA_DESC_SIZE * MV_NFC_MAX_DESC_CHAIN); |
| |
| /* Allocate data DMA descriptors */ |
| nfcCtrl->dataDescBuff.bufVirtPtr = |
| mvOsIoUncachedMalloc(nfcInfo->osHandle, (MV_PDMA_DESC_SIZE * (MV_NFC_MAX_DESC_CHAIN + 1)), |
| &nfcCtrl->dataDescBuff.bufPhysAddr, |
| &nfcCtrl->dataDescBuff.memHandle); |
| if (nfcCtrl->dataDescBuff.bufVirtPtr == NULL) |
| return MV_OUT_OF_CPU_MEM; |
| /* verify allignment to 128bits */ |
| if ((MV_U32) nfcCtrl->dataDescBuff.bufVirtPtr & 0xF) { |
| nfcCtrl->dataDescBuff.bufVirtPtr = |
| (MV_U8 *) (((MV_U32) nfcCtrl->dataDescBuff.bufVirtPtr & ~0xF) + MV_PDMA_DESC_SIZE); |
| nfcCtrl->dataDescBuff.bufPhysAddr = |
| ((nfcCtrl->dataDescBuff.bufPhysAddr & ~0xF) + MV_PDMA_DESC_SIZE); |
| } |
| nfcCtrl->dataDescBuff.bufSize = (MV_PDMA_DESC_SIZE * MV_NFC_MAX_DESC_CHAIN); |
| nfcCtrl->dataDescBuff.dataSize = (MV_PDMA_DESC_SIZE * MV_NFC_MAX_DESC_CHAIN); |
| |
| /* Allocate Data DMA channel */ |
| if (mvPdmaChanAlloc(MV_PDMA_NAND_DATA, nfcInfo->dataPdmaIntMask, &nfcCtrl->dataChanHndl) != MV_OK) |
| return MV_NO_RESOURCE; |
| |
| /* Allocate Command DMA channel */ |
| if (mvPdmaChanAlloc(MV_PDMA_NAND_COMMAND, nfcInfo->cmdPdmaIntMask, &nfcCtrl->cmdChanHndl) != MV_OK) |
| return MV_NO_RESOURCE; |
| } |
| #endif |
| |
| /* Initialize remaining fields in the CTRL structure */ |
| nfcCtrl->autoStatusRead = nfcInfo->autoStatusRead; |
| nfcCtrl->readyBypass = nfcInfo->readyBypass; |
| nfcCtrl->ioMode = nfcInfo->ioMode; |
| nfcCtrl->eccMode = nfcInfo->eccMode; |
| nfcCtrl->ifMode = nfcInfo->ifMode; |
| nfcCtrl->currCs = MV_NFC_CS_NONE; |
| nfcCtrl->regsPhysAddr = nfcInfo->regsPhysAddr; |
| #ifdef MV_INCLUDE_PDMA |
| nfcCtrl->dataPdmaIntMask = nfcInfo->dataPdmaIntMask; |
| nfcCtrl->cmdPdmaIntMask = nfcInfo->cmdPdmaIntMask; |
| #endif |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcSelectChip |
| * |
| * DESCRIPTION: |
| * Set the currently active chip for next commands. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * chip - The chip number to operate on. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_FAIL - On failure |
| *******************************************************************************/ |
| MV_STATUS mvNfcSelectChip(MV_NFC_CTRL *nfcCtrl, MV_NFC_CHIP_SEL chip) |
| { |
| nfcCtrl->currCs = chip; |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcDataLength |
| * |
| * DESCRIPTION: |
| * Get the length of data based on the NFC configuration |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * cmd - Command to be executed |
| * |
| * OUTPUT: |
| * data_len - length of data to be transfered |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_FAIL - On failure |
| *******************************************************************************/ |
| MV_STATUS mvNfcDataLength(MV_NFC_CTRL *nfcCtrl, MV_NFC_CMD_TYPE cmd, MV_U32 *data_len) |
| { |
| /* Decide read data size based on page size */ |
| if (flashDeviceInfo[nfcCtrl->flashIdx].pgSz < MV_NFC_2KB_PAGE) { /* Small Page */ |
| if (nfcCtrl->ifMode == MV_NFC_IF_2X8) { |
| if (nfcCtrl->eccMode == MV_NFC_ECC_HAMMING) |
| *data_len = NFC_RW_SP_G_HMNG_ECC_DATA_LEN; |
| else /* No ECC */ |
| *data_len = NFC_RW_SP_G_NO_ECC_DATA_LEN; |
| } else { |
| if (nfcCtrl->eccMode == MV_NFC_ECC_HAMMING) |
| *data_len = NFC_RW_SP_HMNG_ECC_DATA_LEN; |
| else /* No ECC */ |
| *data_len = NFC_RW_SP_NO_ECC_DATA_LEN; |
| } |
| } else { /* Large Page */ |
| |
| if (nfcCtrl->ifMode == MV_NFC_IF_2X8) { |
| if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_2K) |
| *data_len = NFC_RW_LP_G_BCH_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_1K) |
| *data_len = NFC_RW_LP_BCH1K_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_704B) |
| *data_len = NFC_RW_LP_BCH704B_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_512B) |
| *data_len = NFC_RW_LP_BCH512B_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_HAMMING) |
| *data_len = NFC_RW_LP_G_HMNG_ECC_DATA_LEN; |
| else /* No ECC */ |
| *data_len = NFC_RW_LP_G_NO_ECC_DATA_LEN; |
| } else { |
| if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_2K) |
| *data_len = NFC_RW_LP_BCH_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_1K) |
| *data_len = NFC_RW_LP_BCH1K_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_704B) |
| *data_len = NFC_RW_LP_BCH704B_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_512B) |
| *data_len = NFC_RW_LP_BCH512B_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_HAMMING) |
| *data_len = NFC_RW_LP_HMNG_ECC_DATA_LEN; |
| else /* No ECC */ |
| *data_len = NFC_RW_LP_NO_ECC_DATA_LEN; |
| } |
| } |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcTransferDataLength |
| * |
| * DESCRIPTION: |
| * Get the length of data to be transfered based on the command type and |
| * NFC configuration |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * cmd - Command to be executed |
| * |
| * OUTPUT: |
| * data_len - length of data to be transfered |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_FAIL - On failure |
| *******************************************************************************/ |
| MV_STATUS mvNfcTransferDataLength(MV_NFC_CTRL *nfcCtrl, MV_NFC_CMD_TYPE cmd, MV_U32 *data_len) |
| { |
| switch (cmd) { |
| case MV_NFC_CMD_READ_ID: |
| if (nfcCtrl->ioMode == MV_NFC_PDMA_ACCESS) |
| *data_len = NFC_READ_ID_PDMA_DATA_LEN; |
| else |
| *data_len = NFC_READ_ID_PIO_DATA_LEN; |
| break; |
| |
| case MV_NFC_CMD_READ_STATUS: |
| if (nfcCtrl->ioMode == MV_NFC_PDMA_ACCESS) |
| *data_len = NFC_READ_STATUS_PDMA_DATA_LEN; |
| else |
| *data_len = NFC_READ_STATUS_PIO_DATA_LEN; |
| break; |
| |
| case MV_NFC_CMD_READ_MONOLITHIC: /* Read a single 512B or 2KB page */ |
| case MV_NFC_CMD_READ_MULTIPLE: |
| case MV_NFC_CMD_READ_NAKED: |
| case MV_NFC_CMD_READ_LAST_NAKED: |
| case MV_NFC_CMD_READ_DISPATCH: |
| case MV_NFC_CMD_WRITE_MONOLITHIC: /* Program a single page of 512B or 2KB */ |
| case MV_NFC_CMD_WRITE_MULTIPLE: |
| case MV_NFC_CMD_WRITE_NAKED: |
| case MV_NFC_CMD_WRITE_LAST_NAKED: |
| case MV_NFC_CMD_WRITE_DISPATCH: |
| case MV_NFC_CMD_EXIT_CACHE_READ: |
| case MV_NFC_CMD_CACHE_READ_SEQ: |
| case MV_NFC_CMD_CACHE_READ_START: |
| if (nfcCtrl->ioMode == MV_NFC_PDMA_ACCESS) { |
| /* Decide read data size based on page size */ |
| if (flashDeviceInfo[nfcCtrl->flashIdx].pgSz < MV_NFC_2KB_PAGE) { /* Small Page */ |
| *data_len = NFC_RW_SP_PDMA_DATA_LEN; |
| } else { /* Large Page */ |
| |
| if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_2K) |
| *data_len = NFC_RW_LP_BCH_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_1K) |
| *data_len = NFC_RW_LP_BCH1K_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_704B) |
| *data_len = NFC_RW_LP_BCH704B_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_512B) |
| *data_len = NFC_RW_LP_BCH512B_ECC_DATA_LEN; |
| else /* Hamming and No-Ecc */ |
| *data_len = NFC_RW_LP_PDMA_DATA_LEN; |
| } |
| } else { /* PIO mode */ |
| |
| /* Decide read data size based on page size */ |
| if (flashDeviceInfo[nfcCtrl->flashIdx].pgSz < MV_NFC_2KB_PAGE) { /* Small Page */ |
| if (nfcCtrl->ifMode == MV_NFC_IF_2X8) { |
| if (nfcCtrl->eccMode == MV_NFC_ECC_HAMMING) |
| *data_len = NFC_RW_SP_G_HMNG_ECC_DATA_LEN; |
| else /* No ECC */ |
| *data_len = NFC_RW_SP_G_NO_ECC_DATA_LEN; |
| } else { |
| if (nfcCtrl->eccMode == MV_NFC_ECC_HAMMING) |
| *data_len = NFC_RW_SP_HMNG_ECC_DATA_LEN; |
| else /* No ECC */ |
| *data_len = NFC_RW_SP_NO_ECC_DATA_LEN; |
| } |
| } else { /* Large Page */ |
| |
| if (nfcCtrl->ifMode == MV_NFC_IF_2X8) { |
| if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_2K) |
| *data_len = NFC_RW_LP_G_BCH_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_1K) |
| *data_len = NFC_RW_LP_BCH1K_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_704B) |
| *data_len = NFC_RW_LP_BCH704B_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_512B) |
| *data_len = NFC_RW_LP_BCH512B_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_HAMMING) |
| *data_len = NFC_RW_LP_G_HMNG_ECC_DATA_LEN; |
| else /* No ECC */ |
| *data_len = NFC_RW_LP_G_NO_ECC_DATA_LEN; |
| } else { |
| if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_2K) |
| *data_len = NFC_RW_LP_BCH_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_1K) |
| *data_len = NFC_RW_LP_BCH1K_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_704B) |
| *data_len = NFC_RW_LP_BCH704B_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_BCH_512B) |
| *data_len = NFC_RW_LP_BCH512B_ECC_DATA_LEN; |
| else if (nfcCtrl->eccMode == MV_NFC_ECC_HAMMING) |
| *data_len = NFC_RW_LP_HMNG_ECC_DATA_LEN; |
| else /* No ECC */ |
| *data_len = NFC_RW_LP_NO_ECC_DATA_LEN; |
| } |
| } |
| } |
| break; |
| |
| case MV_NFC_CMD_ERASE: |
| case MV_NFC_CMD_MULTIPLANE_ERASE: |
| case MV_NFC_CMD_RESET: |
| case MV_NFC_CMD_WRITE_DISPATCH_START: |
| case MV_NFC_CMD_WRITE_DISPATCH_END: |
| return MV_BAD_PARAM; |
| |
| default: |
| return MV_BAD_PARAM; |
| |
| }; |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcBuildCommand |
| * |
| * DESCRIPTION: |
| * Build the command buffer |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * cmd - Command to be executed |
| * cmdb - Command buffer cmdb[0:3] to fill |
| * |
| * OUTPUT: |
| * cmdb - Command buffer filled |
| * |
| * RETURN: |
| * None |
| *******************************************************************************/ |
| static MV_STATUS mvNfcBuildCommand(MV_NFC_CTRL *nfcCtrl, MV_NFC_MULTI_CMD *descInfo, MV_U32 *cmdb) |
| { |
| cmdb[0] = 0; |
| cmdb[1] = 0; |
| cmdb[2] = 0; |
| cmdb[3] = 0; |
| if (nfcCtrl->autoStatusRead) |
| cmdb[0] |= NFC_CB0_AUTO_RS_MASK; |
| |
| if ((nfcCtrl->currCs == MV_NFC_CS_1) || (nfcCtrl->currCs == MV_NFC_CS_3)) |
| cmdb[0] |= NFC_CB0_CSEL_MASK; |
| |
| if ((nfcCtrl->currCs == MV_NFC_CS_2) || (nfcCtrl->currCs == MV_NFC_CS_3)) |
| cmdb[2] |= NFC_CB2_CS_2_3_SELECT_MASK; |
| |
| if (nfcCtrl->readyBypass) |
| cmdb[0] |= NFC_CB0_RDY_BYP_MASK; |
| |
| switch (descInfo->cmd) { |
| case MV_NFC_CMD_READ_ID: |
| cmdb[0] |= (flashCmdSet[nfcCtrl->cmdsetIdx].readId & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| cmdb[0] |= ((NFC_READ_ID_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| cmdb[0] |= NFC_CB0_CMD_TYPE_READ_ID; |
| break; |
| |
| case MV_NFC_CMD_READ_STATUS: |
| cmdb[0] |= (flashCmdSet[nfcCtrl->cmdsetIdx].readStatus & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| cmdb[0] |= NFC_CB0_CMD_TYPE_STATUS; |
| break; |
| |
| case MV_NFC_CMD_ERASE: |
| case MV_NFC_CMD_MULTIPLANE_ERASE: |
| |
| if (descInfo->cmd == MV_NFC_CMD_ERASE) |
| cmdb[0] |= (flashCmdSet[nfcCtrl->cmdsetIdx].erase & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| if (descInfo->cmd == MV_NFC_CMD_MULTIPLANE_ERASE) |
| cmdb[0] |= |
| (flashCmdSet[nfcCtrl->cmdsetIdx].multiplaneErase & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| |
| cmdb[0] |= ((NFC_ERASE_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| cmdb[0] |= NFC_CB0_DBC_MASK; |
| cmdb[0] |= NFC_CB0_CMD_TYPE_ERASE; |
| cmdb[1] |= (descInfo->pageAddr & NFC_BLOCK_ADDR_BITS); |
| break; |
| |
| case MV_NFC_CMD_RESET: |
| cmdb[0] |= (flashCmdSet[nfcCtrl->cmdsetIdx].reset & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| cmdb[0] |= NFC_CB0_CMD_TYPE_RESET; |
| break; |
| |
| case MV_NFC_CMD_CACHE_READ_SEQ: |
| cmdb[0] = (flashCmdSet[nfcCtrl->cmdsetIdx].cacheReadSeq & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| break; |
| |
| case MV_NFC_CMD_CACHE_READ_RAND: |
| cmdb[0] = (flashCmdSet[nfcCtrl->cmdsetIdx].cacheReadRand & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| if (flashDeviceInfo[nfcCtrl->flashIdx].pgSz < MV_NFC_2KB_PAGE) { |
| cmdb[1] |= ((descInfo->pageAddr << NFC_SP_PG_OFFS) & NFC_SP_PG_MASK); |
| if (descInfo->pageAddr & ~NFC_SP_PG_MASK) |
| cmdb[0] |= |
| ((NFC_SP_BIG_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| else |
| cmdb[0] |= ((NFC_SP_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| } else { |
| cmdb[0] |= ((NFC_LP_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| cmdb[0] |= NFC_CB0_DBC_MASK; |
| cmdb[1] |= ((descInfo->pageAddr << NFC_LP_PG_OFFS) & NFC_LP_PG_MASK); |
| cmdb[2] |= (descInfo->pageAddr >> (32 - NFC_LP_PG_OFFS)); |
| } |
| cmdb[0] |= NFC_CB0_CMD_TYPE_READ; |
| break; |
| |
| case MV_NFC_CMD_EXIT_CACHE_READ: |
| cmdb[0] |= (flashCmdSet[nfcCtrl->cmdsetIdx].exitCacheRead & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| break; |
| |
| case MV_NFC_CMD_CACHE_READ_START: |
| cmdb[0] |= (flashCmdSet[nfcCtrl->cmdsetIdx].read1 & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| if (flashDeviceInfo[nfcCtrl->flashIdx].pgSz < MV_NFC_2KB_PAGE) { |
| cmdb[1] |= ((descInfo->pageAddr << NFC_SP_PG_OFFS) & NFC_SP_PG_MASK); |
| if (descInfo->pageAddr & ~NFC_SP_PG_MASK) |
| cmdb[0] |= |
| ((NFC_SP_BIG_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| else |
| cmdb[0] |= ((NFC_SP_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| } else { |
| cmdb[0] |= ((NFC_LP_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| cmdb[0] |= NFC_CB0_DBC_MASK; |
| cmdb[1] |= ((descInfo->pageAddr << NFC_LP_PG_OFFS) & NFC_LP_PG_MASK); |
| cmdb[2] |= (descInfo->pageAddr >> (32 - NFC_LP_PG_OFFS)); |
| } |
| cmdb[0] |= NFC_CB0_CMD_TYPE_READ; |
| cmdb[0] |= NFC_CB0_LEN_OVRD_MASK; |
| break; |
| |
| case MV_NFC_CMD_READ_MONOLITHIC: /* Read a single 512B or 2KB page */ |
| case MV_NFC_CMD_READ_MULTIPLE: |
| case MV_NFC_CMD_READ_NAKED: |
| case MV_NFC_CMD_READ_LAST_NAKED: |
| case MV_NFC_CMD_READ_DISPATCH: |
| cmdb[0] |= (flashCmdSet[nfcCtrl->cmdsetIdx].read1 & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| if (flashDeviceInfo[nfcCtrl->flashIdx].pgSz < MV_NFC_2KB_PAGE) { |
| cmdb[1] |= ((descInfo->pageAddr << NFC_SP_PG_OFFS) & NFC_SP_PG_MASK); |
| if (descInfo->pageAddr & ~NFC_SP_PG_MASK) |
| cmdb[0] |= |
| ((NFC_SP_BIG_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| else |
| cmdb[0] |= ((NFC_SP_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| } else { |
| cmdb[0] |= ((NFC_LP_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| cmdb[0] |= NFC_CB0_DBC_MASK; |
| cmdb[1] |= ((descInfo->pageAddr << NFC_LP_PG_OFFS) & NFC_LP_PG_MASK); |
| cmdb[2] |= (descInfo->pageAddr >> (32 - NFC_LP_PG_OFFS)); |
| } |
| cmdb[0] |= NFC_CB0_CMD_TYPE_READ; |
| |
| if (descInfo->length) { |
| cmdb[0] |= NFC_CB0_LEN_OVRD_MASK; |
| cmdb[3] |= (descInfo->length & 0xFFFF); |
| } |
| |
| /* Check for extended command syntax */ |
| switch (descInfo->cmd) { |
| case MV_NFC_CMD_READ_MULTIPLE: |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_MULTIPLE; |
| break; |
| case MV_NFC_CMD_READ_NAKED: |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_NAKED; |
| break; |
| case MV_NFC_CMD_READ_LAST_NAKED: |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_LAST_NAKED; |
| break; |
| case MV_NFC_CMD_READ_DISPATCH: |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_DISPATCH; |
| break; |
| default: |
| break; |
| }; |
| break; |
| |
| case MV_NFC_CMD_WRITE_MONOLITHIC: /* Program a single page of 512B or 2KB */ |
| case MV_NFC_CMD_WRITE_MULTIPLE: |
| /*case MV_NFC_CMD_WRITE_NAKED: */ |
| case MV_NFC_CMD_WRITE_LAST_NAKED: |
| case MV_NFC_CMD_WRITE_DISPATCH: |
| cmdb[0] |= (flashCmdSet[nfcCtrl->cmdsetIdx].program & (NFC_CB0_CMD1_MASK | NFC_CB0_CMD2_MASK)); |
| if (flashDeviceInfo[nfcCtrl->flashIdx].pgSz < MV_NFC_2KB_PAGE) { |
| if (descInfo->pageAddr & ~NFC_SP_PG_MASK) |
| cmdb[0] |= |
| ((NFC_SP_BIG_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| else |
| cmdb[0] |= ((NFC_SP_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| cmdb[1] |= ((descInfo->pageAddr << NFC_SP_PG_OFFS) & NFC_SP_PG_MASK); |
| } else { |
| cmdb[0] |= ((NFC_LP_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| cmdb[1] |= ((descInfo->pageAddr << NFC_LP_PG_OFFS) & NFC_LP_PG_MASK); |
| cmdb[2] |= (descInfo->pageAddr >> (32 - NFC_LP_PG_OFFS)); |
| } |
| cmdb[0] |= NFC_CB0_DBC_MASK; |
| cmdb[0] |= NFC_CB0_CMD_TYPE_WRITE; |
| |
| /* Check for extended syntax */ |
| switch (descInfo->cmd) { |
| case MV_NFC_CMD_WRITE_MULTIPLE: |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_MULTIPLE; |
| break; |
| case MV_NFC_CMD_WRITE_NAKED: |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_NAKED; |
| break; |
| case MV_NFC_CMD_WRITE_LAST_NAKED: |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_LAST_NAKED; |
| break; |
| case MV_NFC_CMD_WRITE_DISPATCH: |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_DISPATCH; |
| break; |
| default: |
| break; |
| }; |
| break; |
| |
| case MV_NFC_CMD_WRITE_DISPATCH_START: |
| cmdb[0] |= (flashCmdSet[nfcCtrl->cmdsetIdx].program & NFC_CB0_CMD1_MASK); |
| if (flashDeviceInfo[nfcCtrl->flashIdx].pgSz < MV_NFC_2KB_PAGE) { |
| if (descInfo->pageAddr & ~NFC_SP_PG_MASK) |
| cmdb[0] |= |
| ((NFC_SP_BIG_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| else |
| cmdb[0] |= ((NFC_SP_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| cmdb[1] |= ((descInfo->pageAddr << NFC_SP_PG_OFFS) & NFC_SP_PG_MASK); |
| } else { |
| cmdb[0] |= ((NFC_LP_READ_ADDR_LEN << NFC_CB0_ADDR_CYC_OFFS) & NFC_CB0_ADDR_CYC_MASK); |
| cmdb[1] |= ((descInfo->pageAddr << NFC_LP_PG_OFFS) & NFC_LP_PG_MASK); |
| cmdb[2] |= (descInfo->pageAddr >> (32 - NFC_LP_PG_OFFS)); |
| } |
| cmdb[0] |= NFC_CB0_CMD_TYPE_WRITE; |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_DISPATCH; |
| break; |
| |
| case MV_NFC_CMD_WRITE_NAKED: |
| cmdb[0] |= NFC_CB0_CMD_TYPE_WRITE; |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_NAKED; |
| if (descInfo->length) { |
| cmdb[0] |= NFC_CB0_LEN_OVRD_MASK; |
| cmdb[3] |= (descInfo->length & 0xFFFF); |
| } |
| break; |
| |
| case MV_NFC_CMD_WRITE_DISPATCH_END: |
| cmdb[0] |= ((flashCmdSet[nfcCtrl->cmdsetIdx].program >> 8) & NFC_CB0_CMD1_MASK); |
| cmdb[0] |= NFC_CB0_CMD_TYPE_WRITE; |
| cmdb[0] |= NFC_CB0_CMD_XTYPE_DISPATCH; |
| break; |
| |
| default: |
| return MV_BAD_PARAM; |
| } |
| |
| /* update page count */ |
| cmdb[2] |= (((descInfo->pageCount - 1) << NFC_PG_CNT_OFFS) & NFC_PG_CNT_MASK); |
| |
| return MV_OK; |
| } |
| |
| #ifdef MV_INCLUDE_PDMA |
| /******************************************************************************* |
| * mvNfcCommandMultiple |
| * |
| * DESCRIPTION: |
| * Issue a command to the NAND controller. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * cmd - The command to issue. |
| * pageAddr - The page number to perform the command on (If the command |
| * requires a flash offset), block address in erase. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_TIMEOUT - Timeout while waiting for command request. |
| * MV_FAIL - On failure |
| *******************************************************************************/ |
| MV_STATUS mvNfcCommandMultiple(MV_NFC_CTRL *nfcCtrl, MV_NFC_MULTI_CMD *descInfo, MV_U32 descCnt) |
| { |
| MV_U32 reg, i, buff; |
| MV_U32 errCode = MV_OK; |
| MV_U32 cmdb[4]; |
| MV_NFC_CMD *cmdVirtPtr = (MV_NFC_CMD *) nfcCtrl->cmdBuff.bufVirtPtr; |
| MV_NFC_CMD *cmdPhysPtr = (MV_NFC_CMD *) nfcCtrl->cmdBuff.bufPhysAddr; |
| |
| MV_PDMA_DESC *cmdDescVirtPtr = (MV_PDMA_DESC *) nfcCtrl->cmdDescBuff.bufVirtPtr; |
| MV_PDMA_DESC *cmdDescPhysPtr = (MV_PDMA_DESC *) nfcCtrl->cmdDescBuff.bufPhysAddr; |
| MV_PDMA_DESC *dataDescVirtPtr = (MV_PDMA_DESC *) nfcCtrl->dataDescBuff.bufVirtPtr; |
| MV_PDMA_DESC *dataDescPhysPtr = (MV_PDMA_DESC *) nfcCtrl->dataDescBuff.bufPhysAddr; |
| MV_U32 xferLen; |
| MV_U32 dataDescCount = 0; |
| MV_U32 nPage; |
| MV_U32 timeout = 10000; |
| MV_STATUS ret; |
| |
| /* Check MAX descriptor count */ |
| if (descCnt > MV_NFC_MAX_DESC_CHAIN) |
| return MV_BAD_PARAM; |
| |
| /* If not in PDMA fail operation */ |
| if (nfcCtrl->ioMode != MV_NFC_PDMA_ACCESS) |
| return MV_BAD_PARAM; |
| |
| /* Check that a chip was selected */ |
| if (nfcCtrl->currCs == MV_NFC_CS_NONE) |
| return MV_FAIL; |
| |
| /* Start the whole command chain through setting the ND_RUN */ |
| /* Setting ND_RUN bit to start the new transaction - verify that controller in idle state */ |
| while (timeout > 0) { |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| if (!(reg & NFC_CTRL_ND_RUN_MASK)) |
| break; |
| timeout--; |
| } |
| if (timeout == 0) |
| return MV_BAD_STATE; |
| |
| for (i = 0; i < descCnt; i++) { |
| if ((descInfo[i].cmd != MV_NFC_CMD_ERASE) && |
| (descInfo[i].cmd != MV_NFC_CMD_MULTIPLANE_ERASE) && |
| (descInfo[i].cmd != MV_NFC_CMD_RESET) && |
| (descInfo[i].cmd != MV_NFC_CMD_EXIT_CACHE_READ) && |
| (descInfo[i].cmd != MV_NFC_CMD_CACHE_READ_START) && |
| (descInfo[i].cmd != MV_NFC_CMD_READ_DISPATCH) && |
| (descInfo[i].cmd != MV_NFC_CMD_WRITE_DISPATCH_START) && |
| (descInfo[i].cmd != MV_NFC_CMD_WRITE_DISPATCH_END)) { |
| /* Get transfer data length for this command type */ |
| mvNfcTransferDataLength(nfcCtrl, descInfo[i].cmd, &xferLen); |
| if (errCode != MV_OK) |
| return errCode; |
| } |
| |
| if (nfcCtrl->eccMode != MV_NFC_ECC_DISABLE) { |
| if ((descInfo[i].cmd == MV_NFC_CMD_READ_ID) || (descInfo[i].cmd == MV_NFC_CMD_READ_STATUS) || |
| (descInfo[i].cmd == MV_NFC_CMD_ERASE) || (descInfo[i].cmd == MV_NFC_CMD_RESET)) { |
| /* disable ECC for these commands */ |
| MV_NAND_REG_BIT_RESET(NFC_CONTROL_REG, NFC_CTRL_ECC_EN_MASK); |
| if (nfcCtrl->eccMode != MV_NFC_ECC_HAMMING) |
| MV_NAND_REG_BIT_RESET(NFC_ECC_CONTROL_REG, NFC_ECC_BCH_EN_MASK); |
| } else { |
| /* enable ECC for all other commands */ |
| MV_NAND_REG_BIT_SET(NFC_CONTROL_REG, NFC_CTRL_ECC_EN_MASK); |
| if (nfcCtrl->eccMode != MV_NFC_ECC_HAMMING) |
| MV_NAND_REG_BIT_SET(NFC_ECC_CONTROL_REG, NFC_ECC_BCH_EN_MASK); |
| } |
| } |
| |
| /* Build the command buffer */ |
| ret = mvNfcBuildCommand(nfcCtrl, &descInfo[i], cmdb); |
| if (ret != MV_OK) |
| return ret; |
| |
| /* Fill Command data */ |
| cmdVirtPtr[i].cmdb0 = cmdb[0]; |
| cmdVirtPtr[i].cmdb1 = cmdb[1]; |
| cmdVirtPtr[i].cmdb2 = cmdb[2]; |
| cmdVirtPtr[i].cmdb3 = cmdb[3]; |
| |
| /* Hook to the previous descriptor if exists */ |
| if (i != 0) { |
| cmdDescVirtPtr[i - 1].physDescPtr = (MV_U32) &cmdDescPhysPtr[i]; |
| cmdVirtPtr[i - 1].cmdb0 |= NFC_CB0_NEXT_CMD_MASK; |
| } |
| |
| /* Fill Command Descriptor */ |
| cmdDescVirtPtr[i].physDescPtr = 0x1; |
| cmdDescVirtPtr[i].physSrcAddr = (MV_U32) &cmdPhysPtr[i]; |
| cmdDescVirtPtr[i].physDestAddr = nfcCtrl->regsPhysAddr + NFC_CMD_BUFF_ADDR; |
| cmdDescVirtPtr[i].commandValue = mvPdmaCommandRegCalc(&nfcCtrl->cmdChanHndl, MV_PDMA_MEM_TO_PERIPH, |
| NFC_CMD_BUFF_SIZE(cmdb[0])); |
| |
| /* Check if data dma need to be operated for this command */ |
| if ((descInfo[i].cmd != MV_NFC_CMD_ERASE) && |
| (descInfo[i].cmd != MV_NFC_CMD_MULTIPLANE_ERASE) && |
| (descInfo[i].cmd != MV_NFC_CMD_RESET) && |
| (descInfo[i].cmd != MV_NFC_CMD_EXIT_CACHE_READ) && |
| (descInfo[i].cmd != MV_NFC_CMD_CACHE_READ_START) && |
| (descInfo[i].cmd != MV_NFC_CMD_READ_DISPATCH) && |
| (descInfo[i].cmd != MV_NFC_CMD_WRITE_DISPATCH_START) && |
| (descInfo[i].cmd != MV_NFC_CMD_WRITE_DISPATCH_END)) { |
| for (nPage = 0; nPage < descInfo[i].pageCount; nPage++) { |
| if (dataDescCount != 0) |
| dataDescVirtPtr[dataDescCount - 1].physDescPtr = |
| (MV_U32) &dataDescPhysPtr[dataDescCount]; |
| /* Fill Data Descriptor */ |
| if ((descInfo[i].cmd == MV_NFC_CMD_READ_MONOLITHIC) || |
| (descInfo[i].cmd == MV_NFC_CMD_READ_MULTIPLE) || |
| (descInfo[i].cmd == MV_NFC_CMD_CACHE_READ_SEQ) || |
| (descInfo[i].cmd == MV_NFC_CMD_EXIT_CACHE_READ) || |
| (descInfo[i].cmd == MV_NFC_CMD_CACHE_READ_RAND) || |
| (descInfo[i].cmd == MV_NFC_CMD_READ_NAKED) || |
| (descInfo[i].cmd == MV_NFC_CMD_READ_LAST_NAKED) || |
| (descInfo[i].cmd == MV_NFC_CMD_READ_DISPATCH) || |
| (descInfo[i].cmd == MV_NFC_CMD_READ_ID) || |
| (descInfo[i].cmd == MV_NFC_CMD_READ_STATUS)) { |
| if (descInfo[i].numSgBuffs == 1) { |
| /* A single buffer, use physAddr */ |
| dataDescVirtPtr[dataDescCount].physSrcAddr = |
| nfcCtrl->regsPhysAddr + NFC_DATA_BUFF_ADDR; |
| dataDescVirtPtr[dataDescCount].physDestAddr = |
| descInfo[i].physAddr + nPage * xferLen; |
| dataDescVirtPtr[dataDescCount].commandValue = |
| mvPdmaCommandRegCalc(&nfcCtrl->dataChanHndl, MV_PDMA_PERIPH_TO_MEM, |
| (descInfo[i].length ? descInfo[i]. |
| length : xferLen)); |
| } else { |
| /* Scatter-gather operation, use sgBuffAdd */ |
| for (buff = 0; buff < descInfo[i].numSgBuffs; buff++) { |
| if (buff != 0) |
| dataDescVirtPtr[dataDescCount - 1].physDescPtr = |
| (MV_U32) &dataDescPhysPtr[dataDescCount]; |
| dataDescVirtPtr[dataDescCount].physSrcAddr = |
| nfcCtrl->regsPhysAddr + NFC_DATA_BUFF_ADDR; |
| dataDescVirtPtr[dataDescCount].physDestAddr = |
| descInfo[i].sgBuffAddr[buff]; |
| dataDescVirtPtr[dataDescCount].commandValue = |
| mvPdmaCommandRegCalc(&nfcCtrl->dataChanHndl, |
| MV_PDMA_PERIPH_TO_MEM, |
| descInfo[i].sgBuffSize[buff]); |
| dataDescCount++; |
| } |
| dataDescCount--; |
| } |
| } else { /* Write */ |
| |
| if (descInfo[i].numSgBuffs == 1) { |
| /* A single buffer, use physAddr */ |
| dataDescVirtPtr[dataDescCount].physSrcAddr = |
| descInfo[i].physAddr + nPage * xferLen; |
| dataDescVirtPtr[dataDescCount].physDestAddr = |
| nfcCtrl->regsPhysAddr + NFC_DATA_BUFF_ADDR; |
| dataDescVirtPtr[dataDescCount].commandValue = |
| mvPdmaCommandRegCalc(&nfcCtrl->dataChanHndl, MV_PDMA_MEM_TO_PERIPH, |
| (descInfo[i].length ? descInfo[i]. |
| length : xferLen)); |
| } else { |
| /* Scatter-gather operation, use sgBuffAdd */ |
| for (buff = 0; buff < descInfo[i].numSgBuffs; buff++) { |
| if (buff != 0) |
| dataDescVirtPtr[dataDescCount - 1].physDescPtr = |
| (MV_U32) &dataDescPhysPtr[dataDescCount]; |
| dataDescVirtPtr[dataDescCount].physSrcAddr = |
| descInfo[i].sgBuffAddr[buff]; |
| dataDescVirtPtr[dataDescCount].physDestAddr = |
| nfcCtrl->regsPhysAddr + NFC_DATA_BUFF_ADDR; |
| dataDescVirtPtr[dataDescCount].commandValue = |
| mvPdmaCommandRegCalc(&nfcCtrl->dataChanHndl, |
| MV_PDMA_MEM_TO_PERIPH, |
| descInfo[i].sgBuffSize[buff]); |
| dataDescCount++; |
| } |
| dataDescCount--; |
| } |
| } |
| |
| dataDescVirtPtr[dataDescCount].physDescPtr = 0x1; |
| dataDescCount++; |
| |
| if (dataDescCount > MV_NFC_MAX_DESC_CHAIN) |
| return MV_OUT_OF_RANGE; |
| } |
| } |
| } |
| |
| #if 0 |
| DBGPRINT((DBGLVL "\ncmdDescPhysPtr = %08x, Count = %d\n", (MV_U32) cmdDescPhysPtr, descCnt)); |
| for (nPage = 0; nPage < descCnt; nPage++) { |
| DBGPRINT((DBGLVL " Command[%d] physDescPtr = %08x\n", nPage, cmdDescVirtPtr[nPage].physDescPtr)); |
| DBGPRINT((DBGLVL " Command[%d] physSrcAddr = %08x\n", nPage, cmdDescVirtPtr[nPage].physSrcAddr)); |
| DBGPRINT((DBGLVL " Command[%d] physDestAddr = %08x\n", nPage, cmdDescVirtPtr[nPage].physDestAddr)); |
| DBGPRINT((DBGLVL " Command[%d] commandValue = %08x\n", nPage, cmdDescVirtPtr[nPage].commandValue)); |
| DBGPRINT((DBGLVL " NDCB0 = %08x, NDCB1 = %08x, NDCB2 = %08x, NDCB3 = %08x\n", |
| cmdVirtPtr[nPage].cmdb0, cmdVirtPtr[nPage].cmdb1, cmdVirtPtr[nPage].cmdb2, |
| cmdVirtPtr[nPage].cmdb3)); |
| } |
| |
| DBGPRINT((DBGLVL "dataDescPhysPtr = %08x, Count = %d\n", (MV_U32) dataDescPhysPtr, dataDescCount)); |
| for (nPage = 0; nPage < dataDescCount; nPage++) { |
| DBGPRINT((DBGLVL " Data[%d] physDescPtr = %08x\n", nPage, dataDescVirtPtr[nPage].physDescPtr)); |
| DBGPRINT((DBGLVL " Data[%d] physSrcAddr = %08x\n", nPage, dataDescVirtPtr[nPage].physSrcAddr)); |
| DBGPRINT((DBGLVL " Data[%d] physDestAddr = %08x\n", nPage, dataDescVirtPtr[nPage].physDestAddr)); |
| DBGPRINT((DBGLVL " Data[%d] commandValue = %08x\n", nPage, dataDescVirtPtr[nPage].commandValue)); |
| } |
| #endif |
| if (dataDescCount) { |
| /* enable interrupts in the last data descriptor. */ |
| mvPdmaCommandIntrEnable(&nfcCtrl->dataChanHndl, &(dataDescVirtPtr[dataDescCount - 1].commandValue)); |
| /* operate the data DMA */ |
| if (mvPdmaChanTransfer(&nfcCtrl->dataChanHndl, MV_PDMA_PERIPH_TO_MEM, |
| 0, 0, 0, (MV_U32) dataDescPhysPtr) != MV_OK) |
| return MV_HW_ERROR; |
| } |
| |
| /* operate the command DMA */ |
| if (mvPdmaChanTransfer(&nfcCtrl->cmdChanHndl, MV_PDMA_MEM_TO_PERIPH, 0, 0, 0, (MV_U32) cmdDescPhysPtr) != MV_OK) |
| return MV_HW_ERROR; |
| |
| /* Clear all old events on the status register */ |
| reg = MV_NAND_REG_READ(NFC_STATUS_REG); |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, reg); |
| |
| /* Start the whole command chain through setting the ND_RUN */ |
| /* Setting ND_RUN bit to start the new transaction - verify that controller in idle state */ |
| while (timeout > 0) { |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| if (!(reg & NFC_CTRL_ND_RUN_MASK)) |
| break; |
| timeout--; |
| } |
| if (timeout == 0) |
| return MV_BAD_STATE; |
| |
| reg |= NFC_CTRL_ND_RUN_MASK; |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, reg); |
| |
| return MV_OK; |
| } |
| #endif |
| |
| /******************************************************************************* |
| * mvNfcCommandPio |
| * |
| * DESCRIPTION: |
| * Issue a command to the NAND controller. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * cmd_descr - The command to issue, page address, page number, data length |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_TIMEOUT - Timeout while waiting for command request. |
| * MV_FAIL - On failure |
| *******************************************************************************/ |
| MV_STATUS mvNfcCommandPio(MV_NFC_CTRL *nfcCtrl, MV_NFC_MULTI_CMD *cmd_desc, MV_BOOL next) |
| { |
| MV_U32 reg; |
| MV_U32 errCode = MV_OK; |
| MV_U32 cmdb_pio[4]; |
| MV_U32 *cmdb; |
| MV_U32 timeout = 10000; |
| MV_STATUS ret; |
| |
| /* Check that a chip was selected */ |
| if (nfcCtrl->currCs == MV_NFC_CS_NONE) |
| return MV_FAIL; |
| |
| /* Clear all old events on the status register */ |
| reg = MV_NAND_REG_READ(NFC_STATUS_REG); |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, reg); |
| |
| /* Setting ND_RUN bit to start the new transaction - verify that controller in idle state */ |
| while (timeout > 0) { |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| if (!(reg & NFC_CTRL_ND_RUN_MASK)) |
| break; |
| timeout--; |
| } |
| |
| if (timeout == 0) |
| return MV_BAD_STATE; |
| |
| reg |= NFC_CTRL_ND_RUN_MASK; |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, reg); |
| |
| /* Wait for Command WRITE request */ |
| mvDfcWait4Complete(NFC_SR_WRCMDREQ_MASK, 1); |
| if (errCode != MV_OK) |
| return errCode; |
| |
| /* Build 12 byte Command */ |
| if (nfcCtrl->ioMode == MV_NFC_PDMA_ACCESS) |
| cmdb = (MV_U32 *) nfcCtrl->cmdBuff.bufVirtPtr; |
| else /* PIO mode */ |
| cmdb = cmdb_pio; |
| |
| if (nfcCtrl->eccMode != MV_NFC_ECC_DISABLE) { |
| switch (cmd_desc->cmd) { |
| case MV_NFC_CMD_READ_MONOLITHIC: |
| case MV_NFC_CMD_READ_MULTIPLE: |
| case MV_NFC_CMD_READ_NAKED: |
| case MV_NFC_CMD_READ_LAST_NAKED: |
| case MV_NFC_CMD_WRITE_MONOLITHIC: |
| case MV_NFC_CMD_WRITE_MULTIPLE: |
| case MV_NFC_CMD_WRITE_NAKED: |
| case MV_NFC_CMD_WRITE_LAST_NAKED: |
| if (nfcCtrl->eccMode != MV_NFC_ECC_DISABLE) { |
| MV_NAND_REG_BIT_SET(NFC_CONTROL_REG, NFC_CTRL_ECC_EN_MASK); |
| if (nfcCtrl->eccMode != MV_NFC_ECC_HAMMING) |
| MV_NAND_REG_BIT_SET(NFC_ECC_CONTROL_REG, NFC_ECC_BCH_EN_MASK); |
| } |
| break; |
| |
| default: |
| /* disable ECC for non-data commands */ |
| MV_NAND_REG_BIT_RESET(NFC_CONTROL_REG, NFC_CTRL_ECC_EN_MASK); |
| MV_NAND_REG_BIT_RESET(NFC_ECC_CONTROL_REG, NFC_ECC_BCH_EN_MASK); |
| break; |
| }; |
| } |
| |
| /* Build the command buffer */ |
| ret = mvNfcBuildCommand(nfcCtrl, cmd_desc, cmdb); |
| if (ret != MV_OK) |
| return ret; |
| |
| /* If next command, link to it */ |
| if (next) |
| cmdb[0] |= NFC_CB0_NEXT_CMD_MASK; |
| |
| /* issue command */ |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, cmdb[0]); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, cmdb[1]); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, cmdb[2]); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, cmdb[3]); |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcStatusGet |
| * |
| * DESCRIPTION: |
| * Retrieve the NAND controller status to monitor the NAND access sequence. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * cmd - The last issued command to get the status for. |
| * |
| * OUTPUT: |
| * value - Relevant only if one of the MV_NFC_STATUS_BBD OR |
| * MV_NFC_STATUS_COR_ERROR errors is turned on. |
| * For MV_NFC_STATUS_COR_ERROR: Holds the errors count. |
| * For MV_NFC_STATUS_BBD: Holds the bad block address. |
| * If error value is not desired, pass NULL as input. |
| * |
| * RETURN: |
| * A bitmask of the MV_NFC_STATUS_XXX status bits. |
| *******************************************************************************/ |
| MV_U32 mvNfcStatusGet(MV_NFC_CTRL *nfcCtrl, MV_NFC_CMD_TYPE cmd, MV_U32 *value) |
| { |
| MV_U32 reg, ret; |
| |
| reg = MV_NAND_REG_READ(NFC_STATUS_REG); |
| if (reg == 0) |
| return 0; |
| |
| if (value) |
| *value = ((reg & NFC_SR_ERR_CNT_MASK) >> NFC_SR_ERR_CNT_OFFS); |
| |
| if ((nfcCtrl->currCs == MV_NFC_CS_0) || (nfcCtrl->currCs == MV_NFC_CS_2)) { |
| /* Clear out all non related interrupts */ |
| reg &= (NFC_SR_CS0_BBD_MASK | NFC_SR_CS0_CMDD_MASK | NFC_SR_CS0_PAGED_MASK | |
| NFC_SR_RDY0_MASK | NFC_SR_WRCMDREQ_MASK | NFC_SR_RDDREQ_MASK | |
| NFC_SR_WRDREQ_MASK | NFC_SR_CORERR_MASK | NFC_SR_UNCERR_MASK); |
| |
| ret = (reg & (NFC_SR_WRCMDREQ_MASK | NFC_SR_RDDREQ_MASK | |
| NFC_SR_WRDREQ_MASK | NFC_SR_CORERR_MASK | NFC_SR_UNCERR_MASK)); |
| |
| if (reg & NFC_SR_CS0_BBD_MASK) |
| ret |= MV_NFC_STATUS_BBD; |
| if (reg & NFC_SR_CS0_CMDD_MASK) |
| ret |= MV_NFC_STATUS_CMDD; |
| if (reg & NFC_SR_CS0_PAGED_MASK) |
| ret |= MV_NFC_STATUS_PAGED; |
| if (reg & NFC_SR_RDY0_MASK) |
| ret |= MV_NFC_STATUS_RDY; |
| } else if ((nfcCtrl->currCs == MV_NFC_CS_1) || (nfcCtrl->currCs == MV_NFC_CS_3)) { |
| reg &= (NFC_SR_CS1_BBD_MASK | NFC_SR_CS1_CMDD_MASK | NFC_SR_CS1_PAGED_MASK | |
| NFC_SR_RDY1_MASK | NFC_SR_WRCMDREQ_MASK | NFC_SR_RDDREQ_MASK | |
| NFC_SR_WRDREQ_MASK | NFC_SR_CORERR_MASK | NFC_SR_UNCERR_MASK); |
| |
| ret = (reg & (NFC_SR_WRCMDREQ_MASK | NFC_SR_RDDREQ_MASK | |
| NFC_SR_WRDREQ_MASK | NFC_SR_CORERR_MASK | NFC_SR_UNCERR_MASK)); |
| |
| if (reg & NFC_SR_CS1_BBD_MASK) |
| ret |= MV_NFC_STATUS_BBD; |
| if (reg & NFC_SR_CS1_CMDD_MASK) |
| ret |= MV_NFC_STATUS_CMDD; |
| if (reg & NFC_SR_CS1_PAGED_MASK) |
| ret |= MV_NFC_STATUS_PAGED; |
| if (reg & NFC_SR_RDY1_MASK) |
| ret |= MV_NFC_STATUS_RDY; |
| } else { |
| reg &= (NFC_SR_WRCMDREQ_MASK | NFC_SR_RDDREQ_MASK | |
| NFC_SR_WRDREQ_MASK | NFC_SR_CORERR_MASK | NFC_SR_UNCERR_MASK); |
| |
| ret = reg; |
| } |
| |
| /* Clear out all reported events */ |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, reg); |
| |
| return ret; |
| } |
| |
| /******************************************************************************* |
| * mvNfcIntrSet |
| * |
| * DESCRIPTION: |
| * Enable / Disable a given set of the Nand controller interrupts. |
| * |
| * INPUT: |
| * inatMask - A bitmask of the interrupts to enable / disable. |
| * enable - MV_TRUE: Unmask the interrupts |
| * MV_FALSE: Mask the interrupts. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_FAIL - On failure |
| *******************************************************************************/ |
| MV_STATUS mvNfcIntrSet(MV_NFC_CTRL *nfcCtrl, MV_U32 intMask, MV_BOOL enable) |
| { |
| MV_U32 reg; |
| MV_U32 msk = (intMask & (NFC_SR_WRCMDREQ_MASK | NFC_SR_RDDREQ_MASK | NFC_SR_WRDREQ_MASK | |
| NFC_SR_CORERR_MASK | NFC_SR_UNCERR_MASK)); |
| |
| if ((nfcCtrl->currCs == MV_NFC_CS_0) || (nfcCtrl->currCs == MV_NFC_CS_2)) { |
| if (intMask & MV_NFC_STATUS_BBD) |
| msk |= NFC_SR_CS0_BBD_MASK; |
| if (intMask & MV_NFC_STATUS_CMDD) |
| msk |= NFC_SR_CS0_CMDD_MASK; |
| if (intMask & MV_NFC_STATUS_PAGED) |
| msk |= NFC_SR_CS0_PAGED_MASK; |
| if (intMask & MV_NFC_STATUS_RDY) |
| msk |= NFC_SR_RDY0_MASK; |
| } else if ((nfcCtrl->currCs == MV_NFC_CS_1) || (nfcCtrl->currCs == MV_NFC_CS_3)) { |
| if (intMask & MV_NFC_STATUS_BBD) |
| msk |= NFC_SR_CS1_BBD_MASK; |
| if (intMask & MV_NFC_STATUS_CMDD) |
| msk |= NFC_SR_CS1_CMDD_MASK; |
| if (intMask & MV_NFC_STATUS_PAGED) |
| msk |= NFC_SR_CS1_PAGED_MASK; |
| if (intMask & MV_NFC_STATUS_RDY) |
| msk |= NFC_SR_RDY0_MASK; |
| } |
| |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| if (enable) |
| reg &= ~msk; |
| else |
| reg |= msk; |
| |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, reg); |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcIntrToStatusConvert |
| * |
| * DESCRIPTION: |
| * Convert logical interrupt bit-mask to status register bit-mask. |
| * |
| * INPUT: |
| * nfcCtrl - NAND control structure. |
| * intMask - Logical interrupts bitmask. |
| * |
| * OUTPUT: |
| * bitmask of interrupt status register bits. |
| * |
| * RETURN: |
| * None. |
| *******************************************************************************/ |
| MV_U32 mvNfcIntrToStatusConvert(MV_NFC_CTRL *nfcCtrl, MV_U32 intMask) |
| { |
| MV_U32 msk = (intMask & (NFC_SR_WRCMDREQ_MASK | NFC_SR_RDDREQ_MASK | NFC_SR_WRDREQ_MASK | |
| NFC_SR_CORERR_MASK | NFC_SR_UNCERR_MASK)); |
| |
| if ((nfcCtrl->currCs == MV_NFC_CS_0) || (nfcCtrl->currCs == MV_NFC_CS_2)) { |
| if (intMask & MV_NFC_STATUS_BBD) |
| msk |= NFC_SR_CS0_BBD_MASK; |
| if (intMask & MV_NFC_STATUS_CMDD) |
| msk |= NFC_SR_CS0_CMDD_MASK; |
| if (intMask & MV_NFC_STATUS_PAGED) |
| msk |= NFC_SR_CS0_PAGED_MASK; |
| if (intMask & MV_NFC_STATUS_RDY) |
| msk |= NFC_SR_RDY0_MASK; |
| } else if ((nfcCtrl->currCs == MV_NFC_CS_1) || (nfcCtrl->currCs == MV_NFC_CS_3)) { |
| if (intMask & MV_NFC_STATUS_BBD) |
| msk |= NFC_SR_CS1_BBD_MASK; |
| if (intMask & MV_NFC_STATUS_CMDD) |
| msk |= NFC_SR_CS1_CMDD_MASK; |
| if (intMask & MV_NFC_STATUS_PAGED) |
| msk |= NFC_SR_CS1_PAGED_MASK; |
| if (intMask & MV_NFC_STATUS_RDY) |
| msk |= NFC_SR_RDY0_MASK; |
| } |
| |
| return msk; |
| |
| } |
| |
| /******************************************************************************* |
| * mvNfcReadWrite |
| * |
| * DESCRIPTION: |
| * Perform a read / write operation of a previously issued command. |
| * When working in PIO mode, this function will perform the read / write |
| * operation from / to the supplied buffer. |
| * when working in PDMA mode, this function will trigger the PDMA to start |
| * the data transfer. |
| * In all cases, the user is responsible to make sure that the data |
| * transfer operation was done successfully by polling the command done bit. |
| * Before calling this function, the Data-Read/Write request interrupts |
| * should be disabled (the one relevant to the command being processed). |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * cmd - The previously issued command. |
| * virtBufAddr - [Relevant only when working in PIO mode] |
| * The virtual address of the buffer to read to / write from. |
| * physBufAddr - [Relevant only when working in PDMA mode] |
| * The physical address of the buffer to read to / write from. |
| * The buffer should be cache coherent for PDMA access. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_FAIL - On failure |
| *******************************************************************************/ |
| MV_STATUS mvNfcReadWrite(MV_NFC_CTRL *nfcCtrl, MV_NFC_CMD_TYPE cmd, MV_U32 *virtBufAddr, MV_U32 physBuffAddr) |
| { |
| MV_U32 data_len = 0; |
| MV_U32 i; |
| MV_STATUS errCode; |
| |
| errCode = mvNfcTransferDataLength(nfcCtrl, cmd, &data_len); |
| if (errCode != MV_OK) |
| return errCode; |
| |
| switch (cmd) { |
| case MV_NFC_CMD_READ_ID: |
| case MV_NFC_CMD_READ_STATUS: |
| case MV_NFC_CMD_READ_MONOLITHIC: /* Read a single 512B or 2KB page */ |
| case MV_NFC_CMD_READ_MULTIPLE: |
| case MV_NFC_CMD_READ_NAKED: |
| case MV_NFC_CMD_READ_LAST_NAKED: |
| case MV_NFC_CMD_READ_DISPATCH: |
| /* Issue command based on IO mode */ |
| if (nfcCtrl->ioMode == MV_NFC_PDMA_ACCESS) { |
| #ifdef MV_INCLUDE_PDMA |
| /* operate the DMA */ |
| if (mvPdmaChanTransfer(&nfcCtrl->dataChanHndl, MV_PDMA_PERIPH_TO_MEM, |
| nfcCtrl->regsPhysAddr + NFC_DATA_BUFF_ADDR, |
| physBuffAddr, data_len, 0) != MV_OK) |
| return MV_HW_ERROR; |
| #else |
| return MV_NOT_SUPPORTED; |
| #endif |
| } else { /* PIO mode */ |
| |
| for (i = 0; i < data_len; i += 4) { |
| *virtBufAddr = MV_LE32_TO_CPU(MV_NAND_REG_READ(NFC_DATA_BUFF_REG)); |
| virtBufAddr++; |
| } |
| } |
| break; |
| |
| case MV_NFC_CMD_WRITE_MONOLITHIC: /* Program a single page of 512B or 2KB */ |
| case MV_NFC_CMD_WRITE_MULTIPLE: |
| case MV_NFC_CMD_WRITE_NAKED: |
| case MV_NFC_CMD_WRITE_LAST_NAKED: |
| case MV_NFC_CMD_WRITE_DISPATCH: |
| /* Issue command based on IO mode */ |
| if (nfcCtrl->ioMode == MV_NFC_PDMA_ACCESS) { |
| #ifdef MV_INCLUDE_PDMA |
| /* operate the DMA */ |
| if (mvPdmaChanTransfer(&nfcCtrl->dataChanHndl, MV_PDMA_MEM_TO_PERIPH, |
| physBuffAddr, nfcCtrl->regsPhysAddr + NFC_DATA_BUFF_ADDR, |
| data_len, 0) != MV_OK) |
| return MV_HW_ERROR; |
| #else |
| return MV_NOT_SUPPORTED; |
| #endif |
| } else { /* PIO mode */ |
| |
| for (i = 0; i < data_len; i += 4) { |
| MV_NAND_REG_WRITE(NFC_DATA_BUFF_REG, MV_CPU_TO_LE32(*virtBufAddr)); |
| virtBufAddr++; |
| } |
| } |
| break; |
| |
| default: |
| return MV_BAD_PARAM; |
| }; |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcReadWritePio |
| * |
| * DESCRIPTION: |
| * Perform PIO read / write operation to the specified buffer. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * buff - The virtual address of the buffer to read to / write from. |
| * data_len - Byte count to transfer |
| * mode - Read / Write/ None |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * None. |
| *******************************************************************************/ |
| MV_VOID mvNfcReadWritePio(MV_NFC_CTRL *nfcCtrl, MV_U32 *buff, MV_U32 data_len, MV_NFC_PIO_RW_MODE mode) |
| { |
| MV_U32 i; |
| |
| switch (mode) { |
| case MV_NFC_PIO_READ: |
| for (i = 0; i < data_len; i += 4) { |
| *buff = MV_LE32_TO_CPU(MV_NAND_REG_READ(NFC_DATA_BUFF_REG)); |
| buff++; |
| /* For BCH ECC check if RDDREQ bit is set every 32 bytes */ |
| if (((nfcCtrl->eccMode == MV_NFC_ECC_BCH_2K) || |
| (nfcCtrl->eccMode == MV_NFC_ECC_BCH_1K) || |
| (nfcCtrl->eccMode == MV_NFC_ECC_BCH_704B) || |
| (nfcCtrl->eccMode == MV_NFC_ECC_BCH_512B)) && |
| ((i & 0x1f) == 0) && (i > 0)) { |
| if (mvDfcWait4Complete(NFC_SR_RDDREQ_MASK, 10) != MV_OK) |
| break; |
| } |
| } |
| break; |
| |
| case MV_NFC_PIO_WRITE: /* Program a single page of 512B or 2KB */ |
| for (i = 0; i < data_len; i += 4) { |
| MV_NAND_REG_WRITE(NFC_DATA_BUFF_REG, MV_CPU_TO_LE32(*buff)); |
| buff++; |
| } |
| break; |
| |
| default: |
| /* nothing to do */ |
| break; |
| }; |
| } |
| |
| /******************************************************************************* |
| * mvNfcAddress2RowConvert |
| * |
| * DESCRIPTION: |
| * Convert an absolute flash address to row index. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * address - The absolute flash address. |
| * |
| * OUTPUT: |
| * row - The row number corresponding to the given address. |
| * colOffset- The column offset within the row. |
| * |
| * RETURN: |
| * None |
| *******************************************************************************/ |
| MV_VOID mvNfcAddress2RowConvert(MV_NFC_CTRL *nfcCtrl, MV_U32 address, MV_U32 *row, MV_U32 *colOffset) |
| { |
| |
| if (flashDeviceInfo[nfcCtrl->flashIdx].pgSz < MV_NFC_2KB_PAGE) { /* Small Page */ |
| *colOffset = (address & 0xFF); |
| *row = (address >> 9); |
| } else { /* Large Page */ |
| |
| *colOffset = (address & (flashDeviceInfo[nfcCtrl->flashIdx].pgSz - 1)); |
| |
| /* Calculate the page bits */ |
| *row = (address >> mvNfcColBits(flashDeviceInfo[nfcCtrl->flashIdx].pgSz)); |
| } |
| } |
| |
| /******************************************************************************* |
| * mvNfcAddress2BlockConvert |
| * |
| * DESCRIPTION: |
| * Convert an absolute flash address to erasable block address |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * address - The absolute flash address. |
| * |
| * OUTPUT: |
| * blk - block address |
| * |
| * RETURN: |
| * None |
| *******************************************************************************/ |
| MV_VOID mvNfcAddress2BlockConvert(MV_NFC_CTRL *nfcCtrl, MV_U32 address, MV_U32 *blk) |
| { |
| *blk = (address / (flashDeviceInfo[nfcCtrl->flashIdx].pgSz * flashDeviceInfo[nfcCtrl->flashIdx].pgPrBlk)); |
| } |
| |
| /******************************************************************************* |
| * mvNfcAddress2BlockConvert |
| * |
| * DESCRIPTION: |
| * Convert an absolute flash address to erasable block address |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * address - The absolute flash address. |
| * |
| * OUTPUT: |
| * blk - block address |
| * |
| * RETURN: |
| * None |
| *******************************************************************************/ |
| MV_8 *mvNfcFlashModelGet(MV_NFC_CTRL *nfcCtrl) |
| { |
| static MV_8 *unk_dev = "Unknown Flash Device"; |
| |
| if (nfcCtrl->flashIdx >= (sizeof(flashDeviceInfo) / sizeof(MV_NFC_FLASH_INFO))) |
| return unk_dev; |
| |
| return flashDeviceInfo[nfcCtrl->flashIdx].model; |
| } |
| |
| /******************************************************************************* |
| * mvNfcFlashPageSizeGet |
| * |
| * DESCRIPTION: |
| * Retrieve the logical page size of a given flash. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * |
| * OUTPUT: |
| * size - Flash page size in bytes. |
| * totalSize - Page size including spare area. |
| * (Pass NULL if not needed). |
| * |
| * RETURN: |
| * MV_NOT_FOUND - Bad flash index. |
| *******************************************************************************/ |
| MV_STATUS mvNfcFlashPageSizeGet(MV_NFC_CTRL *nfcCtrl, MV_U32 *size, MV_U32 *totalSize) |
| { |
| if (nfcCtrl->flashIdx >= (sizeof(flashDeviceInfo) / sizeof(MV_NFC_FLASH_INFO))) |
| return MV_NOT_FOUND; |
| if (size == NULL) |
| return MV_BAD_PTR; |
| |
| if (nfcCtrl->ifMode == MV_NFC_IF_2X8) |
| *size = flashDeviceInfo[nfcCtrl->flashIdx].pgSz << 1; |
| else |
| *size = flashDeviceInfo[nfcCtrl->flashIdx].pgSz; |
| |
| if (totalSize) { |
| mvNfcTransferDataLength(nfcCtrl, MV_NFC_CMD_READ_MONOLITHIC, totalSize); |
| if (nfcCtrl->ifMode == MV_NFC_IF_2X8) |
| *totalSize = (*totalSize) << 1; |
| if (flashDeviceInfo[nfcCtrl->flashIdx].pgSz > MV_NFC_2KB_PAGE) |
| *totalSize = (*totalSize) << 1; |
| } |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcFlashBlockSizeGet |
| * |
| * DESCRIPTION: |
| * Retrieve the logical block size of a given flash. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * |
| * OUTPUT: |
| * size - Flash size in bytes. |
| * |
| * RETURN: |
| * MV_NOT_FOUND - Bad flash index. |
| *******************************************************************************/ |
| MV_STATUS mvNfcFlashBlockSizeGet(MV_NFC_CTRL *nfcCtrl, MV_U32 *size) |
| { |
| if (nfcCtrl->flashIdx >= (sizeof(flashDeviceInfo) / sizeof(MV_NFC_FLASH_INFO))) |
| return MV_NOT_FOUND; |
| if (size == NULL) |
| return MV_BAD_PTR; |
| |
| if (nfcCtrl->ifMode == MV_NFC_IF_2X8) |
| *size = ((flashDeviceInfo[nfcCtrl->flashIdx].pgSz << 1) * flashDeviceInfo[nfcCtrl->flashIdx].pgPrBlk); |
| else |
| *size = (flashDeviceInfo[nfcCtrl->flashIdx].pgSz * flashDeviceInfo[nfcCtrl->flashIdx].pgPrBlk); |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcFlashBlockNumGet |
| * |
| * DESCRIPTION: |
| * Retrieve the number of logical blocks of a given flash. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * |
| * OUTPUT: |
| * numBlocks - Flash number of blocks. |
| * |
| * RETURN: |
| * MV_NOT_FOUND - Bad flash index. |
| *******************************************************************************/ |
| MV_STATUS mvNfcFlashBlockNumGet(MV_NFC_CTRL *nfcCtrl, MV_U32 *numBlocks) |
| { |
| if (nfcCtrl->flashIdx >= (sizeof(flashDeviceInfo) / sizeof(MV_NFC_FLASH_INFO))) |
| return MV_NOT_FOUND; |
| if (numBlocks == NULL) |
| return MV_BAD_PTR; |
| |
| *numBlocks = flashDeviceInfo[nfcCtrl->flashIdx].blkNum; |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcFlashIdGet |
| * |
| * DESCRIPTION: |
| * Retrieve the flash device ID. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * |
| * OUTPUT: |
| * flashId - Flash ID. |
| * |
| * RETURN: |
| * MV_NOT_FOUND - Bad flash index. |
| *******************************************************************************/ |
| MV_STATUS mvNfcFlashIdGet(MV_NFC_CTRL *nfcCtrl, MV_U32 *flashId) |
| { |
| if (nfcCtrl->flashIdx >= (sizeof(flashDeviceInfo) / sizeof(MV_NFC_FLASH_INFO))) |
| return MV_NOT_FOUND; |
| |
| if (flashId == NULL) |
| return MV_BAD_PTR; |
| |
| *flashId = flashDeviceInfo[nfcCtrl->flashIdx].id; |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcUnitStateStore - Store the NFC Unit state. |
| * |
| * DESCRIPTION: |
| * This function stores the NFC unit registers before the unit is suspended. |
| * The stored registers are placed into the input buffer which will be used for |
| * the restore operation. |
| * |
| * INPUT: |
| * regsData - Buffer to store the unit state registers (Must |
| * include at least 64 entries) |
| * len - Number of entries in regsData input buffer. |
| * |
| * OUTPUT: |
| * regsData - Unit state registers. The registers are stored in |
| * pairs of (reg, value). |
| * len - Number of entries in regsData buffer (Must be even). |
| * |
| * RETURS: |
| * MV_ERROR on failure. |
| * MV_OK on success. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvNfcUnitStateStore(MV_U32 *stateData, MV_U32 *len) |
| { |
| MV_U32 i; |
| |
| if ((stateData == NULL) || (len == NULL)) |
| return MV_BAD_PARAM; |
| |
| i = 0; |
| |
| stateData[i++] = NFC_CONTROL_REG; |
| stateData[i++] = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| |
| stateData[i++] = NFC_TIMING_0_REG; |
| stateData[i++] = MV_NAND_REG_READ(NFC_TIMING_0_REG); |
| |
| stateData[i++] = NFC_TIMING_1_REG; |
| stateData[i++] = MV_NAND_REG_READ(NFC_TIMING_1_REG); |
| |
| stateData[i++] = NFC_ECC_CONTROL_REG; |
| stateData[i++] = MV_NAND_REG_READ(NFC_ECC_CONTROL_REG); |
| *len = i; |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvDfcWait4Complete |
| * |
| * DESCRIPTION: |
| * Wait for event or process to complete |
| * |
| * INPUT: |
| * statMask: bit to wait from in status register NDSR |
| * usec: Max uSec to wait for event |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_TIMEOUT - Error accessing the underlying flahs device. |
| *******************************************************************************/ |
| static MV_STATUS mvDfcWait4Complete(MV_U32 statMask, MV_U32 usec) |
| { |
| MV_U32 i, sts; |
| |
| for (i = 0; i < usec; i++) { |
| sts = (MV_NAND_REG_READ(NFC_STATUS_REG) & statMask); |
| if (sts) { |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, sts); |
| return MV_OK; |
| } |
| mvOsUDelay(1); |
| } |
| |
| return MV_TIMEOUT; |
| } |
| |
| /******************************************************************************* |
| * mvNfcDeviceFeatureSet |
| * |
| * DESCRIPTION: |
| * Set a NAND device feature according to user's request. |
| * |
| * INPUT: |
| * nfcCtrl - NFC control structure. |
| * cmd - Command to be sent to NAND device. |
| * addr - Address of the special feature. |
| * data0 - First 4 bytes of data to be written. |
| * data1 - Bytes 4-7 of data. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_TIMEOUT - Error accessing the underlying flahs device. |
| *******************************************************************************/ |
| static MV_STATUS mvNfcDeviceFeatureSet(MV_NFC_CTRL *nfcCtrl, MV_U8 cmd, MV_U8 addr, MV_U32 data0, MV_U32 data1) |
| { |
| MV_U32 reg; |
| MV_U32 errCode = MV_OK; |
| MV_U32 timeout = 10000; |
| |
| /* Clear all old events on the status register */ |
| reg = MV_NAND_REG_READ(NFC_STATUS_REG); |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, reg); |
| |
| /* Setting ND_RUN bit to start the new transaction */ |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| reg |= NFC_CTRL_ND_RUN_MASK; |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, reg); |
| |
| /* Wait for Command WRITE request */ |
| errCode = mvDfcWait4Complete(NFC_SR_WRCMDREQ_MASK, 1); |
| if (errCode != MV_OK) |
| goto Error_1; |
| |
| reg = MV_NAND_REG_READ(NFC_STATUS_REG); |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, reg); |
| |
| /* Send Naked Command Dispatch Command*/ |
| reg = cmd; |
| reg |= (0x1 << NFC_CB0_ADDR_CYC_OFFS); |
| reg |= NFC_CB0_CMD_XTYPE_MULTIPLE; |
| reg |= NFC_CB0_CMD_TYPE_WRITE; |
| reg |= NFC_CB0_LEN_OVRD_MASK; |
| |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, reg); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, addr); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x0); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x8); |
| |
| /* Wait for Data READ request */ |
| errCode = mvDfcWait4Complete(NFC_SR_WRDREQ_MASK, 10); |
| if (errCode != MV_OK) |
| return errCode; |
| |
| mvOsUDelay(100); |
| |
| MV_NAND_REG_WRITE(NFC_DATA_BUFF_REG, data0); |
| MV_NAND_REG_WRITE(NFC_DATA_BUFF_REG, data1); |
| |
| /* Wait for Data READ request */ |
| errCode = mvDfcWait4Complete(NFC_SR_RDY0_MASK, 10); |
| if (errCode != MV_OK) |
| return errCode; |
| |
| /* Wait for ND_RUN bit to get cleared. */ |
| while (timeout > 0) { |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| if (!(reg & NFC_CTRL_ND_RUN_MASK)) |
| break; |
| timeout--; |
| } |
| if (timeout == 0) |
| return MV_BAD_STATE; |
| |
| Error_1: |
| return errCode; |
| } |
| |
| /******************************************************************************* |
| * mvNfcDeviceFeatureGet |
| * |
| * DESCRIPTION: |
| * Get a NAND device feature according to user's request. |
| * |
| * INPUT: |
| * nfcCtrl - NFC control structure. |
| * cmd - Command to be sent to NAND device. |
| * addr - Address of the special feature. |
| * |
| * OUTPUT: |
| * data0 - First 4 bytes of the data. |
| * data1 - Bytes 4-7 of data. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_TIMEOUT - Error accessing the underlying flahs device. |
| *******************************************************************************/ |
| static MV_STATUS mvNfcDeviceFeatureGet(MV_NFC_CTRL *nfcCtrl, MV_U8 cmd, MV_U8 addr, MV_U32 *data0, MV_U32 *data1) |
| { |
| MV_U32 reg; |
| MV_U32 errCode = MV_OK; |
| MV_U32 timeout = 10000; |
| |
| /* Clear all old events on the status register */ |
| reg = MV_NAND_REG_READ(NFC_STATUS_REG); |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, reg); |
| |
| /* Setting ND_RUN bit to start the new transaction */ |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| reg |= NFC_CTRL_ND_RUN_MASK; |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, reg); |
| |
| /* Wait for Command WRITE request */ |
| errCode = mvDfcWait4Complete(NFC_SR_WRCMDREQ_MASK, 1); |
| if (errCode != MV_OK) |
| goto Error_2; |
| |
| reg = MV_NAND_REG_READ(NFC_STATUS_REG); |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, reg); |
| |
| /* Send Read Command */ |
| reg = cmd; |
| reg |= (0x1 << NFC_CB0_ADDR_CYC_OFFS); |
| reg |= NFC_CB0_CMD_XTYPE_MULTIPLE; |
| reg |= NFC_CB0_CMD_TYPE_READ; |
| reg |= NFC_CB0_LEN_OVRD_MASK; |
| |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, reg); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, addr); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x0); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x8); |
| |
| /* Wait for READY */ |
| errCode = mvDfcWait4Complete(NFC_SR_RDY0_MASK, 10); |
| if (errCode != MV_OK) |
| return errCode; |
| |
| udelay(500); |
| /* Send Last-Naked Read Command */ |
| reg = 0x0; |
| reg |= NFC_CB0_CMD_XTYPE_LAST_NAKED; |
| reg |= NFC_CB0_CMD_TYPE_READ; |
| reg |= NFC_CB0_LEN_OVRD_MASK; |
| |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, reg); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x0); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x0); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x8); |
| |
| /* Wait for Data READ request */ |
| errCode = mvDfcWait4Complete(NFC_SR_RDDREQ_MASK, 100); |
| if (errCode != MV_OK) |
| return errCode; |
| |
| /* Read the data + read 4 bogus bytes */ |
| *data0 = MV_NAND_REG_READ(NFC_DATA_BUFF_REG); |
| *data1 = MV_NAND_REG_READ(NFC_DATA_BUFF_REG); |
| |
| /* Wait for ND_RUN bit to get cleared. */ |
| while (timeout > 0) { |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| if (!(reg & NFC_CTRL_ND_RUN_MASK)) |
| break; |
| timeout--; |
| } |
| if (timeout == 0) |
| return MV_BAD_STATE; |
| Error_2: |
| return errCode; |
| } |
| |
| /******************************************************************************* |
| * mvNfcDeviceModeSet |
| * |
| * DESCRIPTION: |
| * Change flash working mode according to the flags |
| * field. |
| * |
| * INPUT: |
| * nfcCtrl - NFC control structure. |
| * flInfo - flash info structure |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_BAD_VALUE - Wrong mode |
| * MV_TIMEOUT - Error accessing the underlying flahs device. |
| *******************************************************************************/ |
| static MV_STATUS mvNfcDeviceModeSet(MV_NFC_CTRL *nfcCtrl, MV_NFC_ONFI_MODE mode) |
| { |
| MV_STATUS ret; |
| MV_U32 d0 = 0, d1 = 0; |
| |
| if (mode == MV_NFC_ONFI_MODE_3) { |
| /* Switch to faster mode */ |
| ret = mvNfcDeviceFeatureSet(nfcCtrl, 0xEF, 0x01, 0x03, 0); |
| if (ret != MV_OK) |
| return ret; |
| |
| /* Verify mode setting */ |
| mvNfcDeviceFeatureGet(nfcCtrl, 0xEE, 0x01, &d0, &d1); |
| if (d0 != 3) |
| return MV_BAD_VALUE; |
| } else |
| return MV_FAIL; |
| |
| return MV_OK; |
| } |
| |
| |
| MV_STATUS mvNfcReset(void) |
| { |
| MV_U32 reg; |
| MV_U32 errCode = MV_OK; |
| MV_U32 timeout = 10000; |
| |
| /* Clear all old events on the status register */ |
| reg = MV_NAND_REG_READ(NFC_STATUS_REG); |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, reg); |
| |
| /* Setting ND_RUN bit to start the new transaction */ |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| reg |= NFC_CTRL_ND_RUN_MASK; |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, reg); |
| |
| /* Wait for Command WRITE request */ |
| errCode = mvDfcWait4Complete(NFC_SR_WRCMDREQ_MASK, 1); |
| if (errCode != MV_OK) |
| goto Error_3; |
| |
| /* Send Command */ |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x00A000FF); /* DFC_NDCB0_RESET */ |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x0); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x0); |
| |
| /* Wait for Command completion */ |
| errCode = mvDfcWait4Complete(NFC_SR_RDY0_MASK, 1000); |
| if (errCode != MV_OK) |
| goto Error_3; |
| |
| /* Wait for ND_RUN bit to get cleared. */ |
| while (timeout > 0) { |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| if (!(reg & NFC_CTRL_ND_RUN_MASK)) |
| break; |
| timeout--; |
| } |
| if (timeout == 0) |
| return MV_BAD_STATE; |
| |
| Error_3: |
| return errCode; |
| } |
| |
| /******************************************************************************* |
| * mvNfcReadIdNative |
| * |
| * DESCRIPTION: |
| * Read the flash Manufacturer and device ID in PIO mode. |
| * |
| * INPUT: |
| * None. |
| * |
| * OUTPUT: |
| * id: Manufacturer and Device Id detected (valid only if return is MV_OK). |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_TIMEOUT - Error accessing the underlying flahs device. |
| * MV_FAIL - On failure |
| *******************************************************************************/ |
| static MV_STATUS mvNfcReadIdNative(MV_NFC_CHIP_SEL cs, MV_U16 *id) |
| { |
| MV_U32 reg, cmdb0 = 0, cmdb2 = 0; |
| MV_U32 errCode = MV_OK; |
| |
| /* Clear all old events on the status register */ |
| reg = MV_NAND_REG_READ(NFC_STATUS_REG); |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, reg); |
| |
| /* Setting ND_RUN bit to start the new transaction */ |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| reg |= NFC_CTRL_ND_RUN_MASK; |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, reg); |
| |
| /* Wait for Command WRITE request */ |
| errCode = mvDfcWait4Complete(NFC_SR_WRCMDREQ_MASK, 1); |
| if (errCode != MV_OK) |
| return errCode; |
| |
| /* Send Command */ |
| reg = NFC_NATIVE_READ_ID_CMD; |
| reg |= (0x1 << NFC_CB0_ADDR_CYC_OFFS); |
| reg |= NFC_CB0_CMD_TYPE_READ_ID; |
| cmdb0 = reg; |
| if ((cs == MV_NFC_CS_1) || (cs == MV_NFC_CS_3)) |
| cmdb0 |= NFC_CB0_CSEL_MASK; |
| |
| if ((cs == MV_NFC_CS_2) || (cs == MV_NFC_CS_3)) |
| cmdb2 |= NFC_CB2_CS_2_3_SELECT_MASK; |
| |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, cmdb0); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0x0); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, cmdb2); |
| |
| /* Wait for Data READ request */ |
| mvDfcWait4Complete(NFC_SR_RDDREQ_MASK, 10); |
| if (errCode != MV_OK) |
| return errCode; |
| |
| /* Read the read ID bytes. + read 4 bogus bytes */ |
| *id = (MV_U16) (MV_NAND_REG_READ(NFC_DATA_BUFF_REG) & 0xFFFF); |
| reg = MV_NAND_REG_READ(NFC_DATA_BUFF_REG); /* dummy read to complete 8 bytes */ |
| |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| if (reg & NFC_CTRL_ND_RUN_MASK) { |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, (reg & ~NFC_CTRL_ND_RUN_MASK)); |
| return MV_BAD_STATE; |
| } |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcTimingSet |
| * |
| * DESCRIPTION: |
| * Set all flash timing parameters for optimized operation |
| * |
| * INPUT: |
| * nand_clock - nand clock frequency, |
| * flInfo - timing information |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK -On success, |
| * MV_FAIL -On failure |
| *******************************************************************************/ |
| static MV_STATUS mvNfcTimingSet(MV_U32 nand_clock, MV_NFC_FLASH_INFO *flInfo) |
| { |
| MV_U32 reg, i; |
| MV_U32 clk2ns; |
| MV_U32 trc, trp, trh, twc, twp, twh; |
| MV_U32 tadl_nfc, tch_nfc, tcs_nfc, twh_nfc, twp_nfc, trh_nfc, trp_nfc; |
| MV_U32 tr_nfc, trhw_nfc, twhr_nfc, tar_nfc; |
| MV_U32 tr_pre_nfc = 0; |
| /* MV_U32 ret = MV_OK; */ |
| |
| clk2ns = DIV_ROUND_UP(_1GHz, nand_clock); |
| |
| /* Calculate legal read timing */ |
| trc = ns_clk(flInfo->tRC, clk2ns); |
| trp = ns_clk(flInfo->tRP, clk2ns); |
| trh = ns_clk(flInfo->tRH, clk2ns); |
| if (trc > (trp + trh)) |
| trh = (trc - trp); |
| |
| /* Calculate legal write timing */ |
| twc = ns_clk(flInfo->tWC, clk2ns); |
| twp = ns_clk(flInfo->tWP, clk2ns); |
| twh = ns_clk(flInfo->tWH, clk2ns); |
| if (twc > (twp + twh)) |
| twh = (twc - twp); |
| |
| /* Calculate the timing configurations for register0 */ |
| tadl_nfc = (ns_clk(flInfo->tADL, clk2ns) - maxx(ns_clk(flInfo->tCH, clk2ns), twh)); |
| tch_nfc = (ns_clk(flInfo->tCH, clk2ns) - 1); |
| tcs_nfc = (ns_clk(flInfo->tCS, clk2ns) - twp - 1); |
| twh_nfc = (twh - 1); |
| twp_nfc = (twp - 1); |
| trh_nfc = (trh - 1); |
| trp_nfc = (trp - 1); |
| |
| if (check_limit(tadl_nfc, 5) != tadl_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| tadl_nfc = check_limit(tadl_nfc, 5); |
| } |
| |
| if (check_limit(tch_nfc, 3) != tch_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| tch_nfc = check_limit(tch_nfc, 3); |
| } |
| |
| if (check_limit(tcs_nfc, 3) != tcs_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| tcs_nfc = check_limit(tcs_nfc, 3); |
| } |
| |
| if (check_limit(twh_nfc, 3) != twh_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| twh_nfc = check_limit(twh_nfc, 3); |
| } |
| |
| if (check_limit(twp_nfc, 3) != twp_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| twp_nfc = check_limit(twp_nfc, 3); |
| } |
| |
| if (check_limit(trh_nfc, 3) != trh_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| trh_nfc = check_limit(trh_nfc, 3); |
| } |
| |
| if (check_limit(trp_nfc, 4) != trp_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| trp_nfc = check_limit(trp_nfc, 4); |
| } |
| |
| reg = ((tadl_nfc << NFC_TMNG0_TADL_OFFS) | |
| (0x1 << NFC_TMNG0_SEL_CNTR_OFFS) | |
| (0x4 << NFC_TMNG0_RD_CNT_DEL_OFFS) | |
| (tch_nfc << NFC_TMNG0_TCH_OFFS) | |
| (tcs_nfc << NFC_TMNG0_TCS_OFFS) | |
| (twh_nfc << NFC_TMNG0_TWH_OFFS) | |
| (twp_nfc << NFC_TMNG0_TWP_OFFS) | |
| (0x0 << NFC_TMNG0_SEL_NRE_EDGE_OFFS) | |
| ((trp_nfc >> 3) << NFC_TMNG0_ETRP_OFFS) | |
| (trh_nfc << NFC_TMNG0_TRH_OFFS) | |
| ((trp_nfc & 0x7) << NFC_TMNG0_TRP_OFFS)); |
| MV_NAND_REG_WRITE(NFC_TIMING_0_REG, reg); |
| |
| /* Calculate the timing configurations for register1 */ |
| tr_nfc = (ns_clk(flInfo->tR, clk2ns) - tch_nfc - 3); |
| trhw_nfc = (ns_clk(flInfo->tRHW, clk2ns) % 16) ? ((ns_clk(flInfo->tRHW, |
| clk2ns) / 16) + 1) : (ns_clk(flInfo->tRHW, clk2ns) / 16); |
| |
| /* |
| * For simplicity Assuming that tar == twhr |
| * loop over all 16 possible values of tWHR_NFC and find smallest possible value (if possible!!!) |
| */ |
| twhr_nfc = 17; /* big number */ |
| for (i = 0; i < 16; i++) { |
| if ((maxx(twh_nfc, tch_nfc) + maxx(i, maxx(0, i - maxx(twh_nfc, tch_nfc))) + 2) >= |
| ns_clk(flInfo->tWHR, clk2ns)) |
| if (twhr_nfc > i) |
| twhr_nfc = i; |
| } |
| |
| if (twhr_nfc >= 16) { |
| twhr_nfc = 15; /* worst case - best we can do */ |
| /* ret = MV_OUT_OF_RANGE; */ |
| } |
| |
| tar_nfc = twhr_nfc; /* our initial assumption */ |
| |
| if (tr_nfc > 0xFFFF) { |
| tr_pre_nfc = 1; |
| tr_nfc = ((tr_nfc % 16) ? ((tr_nfc/16) + 1) : (tr_nfc/16)); |
| } |
| |
| #ifndef MTD_NAND_NFC_NEGLECT_RNB |
| /* If RnBx signal is used, then override tR to a very small and legal value */ |
| tr_nfc = 0xFF; |
| tr_pre_nfc = 0; |
| #endif |
| |
| if (check_limit(tr_nfc, 16) != tr_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| tr_nfc = check_limit(tr_nfc, 16); |
| } |
| |
| if (check_limit(trhw_nfc, 2) != trhw_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| trhw_nfc = check_limit(trhw_nfc, 2); |
| } |
| |
| if (check_limit(twhr_nfc, 4) != twhr_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| twhr_nfc = check_limit(twhr_nfc, 4); |
| } |
| |
| if (check_limit(tar_nfc, 4) != tar_nfc) { |
| /* ret = MV_OUT_OF_RANGE; */ |
| tar_nfc = check_limit(tar_nfc, 5); |
| } |
| |
| reg = ((tr_nfc << NFC_TMNG1_TR_OFFS) | |
| (tr_pre_nfc << NFC_TMNG1_PRESCALE_OFFS) | |
| (trhw_nfc << NFC_TMNG1_TRHW_OFFS) | |
| (twhr_nfc << NFC_TMNG1_TWHR_OFFS) | |
| (tar_nfc << NFC_TMNG1_TAR_OFFS)); |
| #ifndef MTD_NAND_NFC_NEGLECT_RNB |
| reg |= (0x1 << NFC_TMNG1_WAIT_MODE_OFFS); |
| #endif |
| MV_NAND_REG_WRITE(NFC_TIMING_1_REG, reg); |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvNfcColBits |
| * |
| * DESCRIPTION: |
| * Calculate number of bits representing column part of the address |
| * |
| * INPUT: |
| pg_size: page size |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * Number of bits representing a column |
| *******************************************************************************/ |
| static MV_U32 mvNfcColBits(MV_U32 pg_size) |
| { |
| MV_U32 shift = 0; |
| while (pg_size) { |
| ++shift; |
| pg_size >>= 1; |
| }; |
| |
| return shift - 1; |
| } |
| |
| /******************************************************************************* |
| * mvNfcEccModeSet |
| * |
| * DESCRIPTION: |
| * Set the ECC mode at runtime to BCH, Hamming or No Ecc. |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * MV_NFC_ECC_MODE eccMode: ECC type (BCH, Hamming or No Ecc) |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * previous ECC mode. |
| *******************************************************************************/ |
| MV_NFC_ECC_MODE mvNfcEccModeSet(MV_NFC_CTRL *nfcCtrl, MV_NFC_ECC_MODE eccMode) |
| { |
| MV_NFC_ECC_MODE prevEccMode; |
| |
| prevEccMode = nfcCtrl->eccMode; |
| nfcCtrl->eccMode = eccMode; |
| return prevEccMode; |
| } |
| |
| /******************************************************************************* |
| * mvNfcBadBlockPageNumber |
| * |
| * DESCRIPTION: |
| * Get the page number within the block holding the bad block indication |
| * |
| * INPUT: |
| * nfcCtrl - Nand control structure. |
| * |
| * OUTPUT: |
| * None |
| * |
| * RETURN: |
| * page number having the bad block indicator |
| *******************************************************************************/ |
| MV_U32 mvNfcBadBlockPageNumber(MV_NFC_CTRL *nfcCtrl) |
| { |
| return flashDeviceInfo[nfcCtrl->flashIdx].bb_page; |
| } |
| |
| |
| /*******************************************************************************/ |
| #ifdef MV_CPU_LE |
| #define build_uint16(byte1, byte0) ((MV_U16) ((byte0 << 8) | byte1)); |
| #define build_uint32(byte3, byte2, byte1, byte0) \ |
| ((MV_U32) ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3)); |
| #endif |
| /*******************************************************************************/ |
| #ifdef MV_CPU_BE |
| #define build_uint16(byte1, byte0) ((MV_U16) ((byte1 << 8) | byte0)); |
| #define build_uint32(byte3, byte2, byte1, byte0) \ |
| ((MV_U32) ((byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0)); |
| #endif |
| /******************************************************************************* |
| * mvNfcReadParamPage |
| * |
| * DESCRIPTION: |
| * The READ PARAMETER PAGE (ECh) command is used to read the ONFI parameter |
| * page programmed into the target. This command is accepted by the target |
| * only when all die (LUNs) on the target are idle |
| * |
| * INPUT: |
| * nfcCtrl - NFC control structure. |
| * buf - buff (size 256). |
| * |
| * OUTPUT: |
| * data0 - First 4 bytes of the data. |
| * data1 - Bytes 4-7 of data. |
| * |
| * RETURN: |
| * MV_OK - On success, |
| * MV_TIMEOUT - Error accessing the underlying flahs device. |
| *******************************************************************************/ |
| static MV_STATUS mvNfcReadParamPage(struct parameter_page_t *ppage) |
| { |
| MV_U32 reg, i; |
| MV_U8 rbuf[NUM_OF_PPAGE_BYTES]; |
| MV_U32 *pBuf = (MV_U32 *)rbuf; |
| |
| MV_U32 errCode = MV_OK; |
| MV_U32 timeout = 10000; |
| |
| /* Clear all old events on the status register */ |
| reg = MV_NAND_REG_READ(NFC_STATUS_REG); |
| MV_NAND_REG_WRITE(NFC_STATUS_REG, reg); |
| |
| /* Setting ND_RUN bit to start the new transaction */ |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| reg |= NFC_CTRL_ND_RUN_MASK; |
| MV_NAND_REG_WRITE(NFC_CONTROL_REG, reg); |
| |
| /* Wait for Command WRITE request */ |
| errCode = mvDfcWait4Complete(NFC_SR_WRCMDREQ_MASK, 1); |
| if (errCode != MV_OK) |
| return errCode; |
| |
| /* Send Read Command */ |
| reg = 0xEC; |
| reg |= (0x1 << NFC_CB0_ADDR_CYC_OFFS); |
| reg |= NFC_CB0_CMD_XTYPE_MULTIPLE; |
| reg |= NFC_CB0_CMD_TYPE_READ; |
| reg |= NFC_CB0_LEN_OVRD_MASK; |
| |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, reg); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 0); |
| MV_NAND_REG_WRITE(NFC_COMMAND_BUFF_0_REG, 128); |
| |
| /* Wait for READY */ |
| errCode = mvDfcWait4Complete(NFC_SR_RDY0_MASK, 100); |
| if (errCode != MV_OK) |
| return errCode; |
| mvOsUDelay(100); |
| |
| /* Read the data 129 bytes */ |
| for (i = 0; i < (NUM_OF_PPAGE_BYTES / 4); i++) |
| *pBuf++ = MV_NAND_REG_READ(NFC_DATA_BUFF_REG); |
| |
| /* Wait for ND_RUN bit to get cleared. */ |
| while (timeout > 0) { |
| reg = MV_NAND_REG_READ(NFC_CONTROL_REG); |
| if (!(reg & NFC_CTRL_ND_RUN_MASK)) |
| break; |
| timeout--; |
| } |
| if (timeout == 0) |
| return MV_BAD_STATE; |
| /* |
| * Fill the parameter page data structure in the right way |
| */ |
| |
| /* Parameter page signature (ONFI) */ |
| mvOsMemset(ppage, 0, sizeof(struct parameter_page_t)); |
| mvOsMemcpy(ppage->signature, rbuf, 4); |
| |
| /* check if the buffer contains a valid ONFI parameter page */ |
| if (strcmp(ppage->signature, "ONFI")) |
| return MV_BAD_PARAM; |
| |
| ppage->rev_num = build_uint16(rbuf[4], rbuf[5]); /* Revision number */ |
| ppage->feature = build_uint16(rbuf[6], rbuf[7]); /* Features supported */ |
| ppage->command = build_uint16(rbuf[8], rbuf[9]); /* Optional commands supported */ |
| mvOsMemcpy(ppage->manufacturer, &rbuf[32], 13); /* Device manufacturer */ |
| mvOsMemcpy(ppage->model, &rbuf[44], 21); /* Device part number */ |
| ppage->jedec_id = rbuf[64]; /* Manufacturer ID (Micron = 2Ch) */ |
| ppage->date_code = build_uint16(rbuf[65], rbuf[66]); /* Date code */ |
| |
| /* Number of data bytes per page */ |
| ppage->data_bytes_per_page = build_uint32(rbuf[80], rbuf[81], rbuf[82], rbuf[83]); |
| |
| /* Number of spare bytes per page */ |
| ppage->spare_bytes_per_page = build_uint16(rbuf[84], rbuf[85]); |
| |
| /* Number of data bytes per partial page */ |
| ppage->data_bytes_per_partial_page = build_uint32(rbuf[86], rbuf[87], rbuf[88], rbuf[89]); |
| |
| /* Number of spare bytes per partial page */ |
| ppage->spare_bytes_per_partial_page = build_uint16(rbuf[90], rbuf[91]); |
| |
| /* Number of pages per block */ |
| ppage->pages_per_block = build_uint32(rbuf[92], rbuf[93], rbuf[94], rbuf[95]); |
| |
| /* Number of blocks per unit */ |
| ppage->blocks_per_lun = build_uint32(rbuf[96], rbuf[97], rbuf[98], rbuf[99]); |
| |
| ppage->luns_per_ce = rbuf[100]; /* Number of logical units (LUN) per chip enable */ |
| ppage->num_addr_cycles = rbuf[101]; /*Number of address cycles */ |
| ppage->bit_per_cell = rbuf[102]; /* Number of bits per cell (1 = SLC; >1= MLC) */ |
| ppage->max_bad_blocks_per_lun = build_uint16(rbuf[103], rbuf[104]); /* Bad blocks maximum per unit */ |
| ppage->block_endurance = build_uint16(rbuf[105], rbuf[106]); /* Block endurance */ |
| ppage->guarenteed_valid_blocks = rbuf[107]; /* Guaranteed valid blocks at beginning of target */ |
| |
| /* Block endurance for guaranteed valid blocks */ |
| ppage->guarenteed_valid_blocks = build_uint16(rbuf[108], rbuf[109]); |
| ppage->num_programs_per_page = rbuf[110]; /* Number of programs per page */ |
| ppage->partial_prog_attr = rbuf[111]; /* Partial programming attributes */ |
| ppage->num_ECC_bits = rbuf[112]; /* Number of bits ECC bits */ |
| ppage->num_interleaved_addr_bits = rbuf[113]; /* Number of interleaved address bits */ |
| ppage->interleaved_op_attr = rbuf[114]; /* Interleaved operation attributes */ |
| |
| return errCode; |
| } |
| |
| /******************************************************************************* |
| * mvNfcPrintParamPage |
| * |
| * DESCRIPTION: |
| * Print the READ PARAMETER PAGE (ECh - the ONFI parameter ) |
| * |
| * INPUT: |
| * struct parameter_page_t |
| * |
| * OUTPUT: |
| * |
| * RETURN: |
| *******************************************************************************/ |
| void mvNfcPrintParamPage(void) |
| { |
| struct parameter_page_t *ppage = ¶mPage; |
| |
| if (strcmp(ppage->signature, "ONFI") != 0) |
| return; |
| |
| mvOsPrintf("ONFI structure\n"); |
| mvOsPrintf("signature = %s\n", ppage->signature); |
| mvOsPrintf("Revision number = 0x%x, \tFeatures supported =0x%x\n", ppage->rev_num, ppage->feature); |
| mvOsPrintf("Optional commands supported=0x%x\n", ppage->command); |
| mvOsPrintf("manufacturer = %s\n", ppage->manufacturer); |
| mvOsPrintf("model = %s\n", ppage->model); |
| mvOsPrintf("data bytes per page= %d\n", ppage->data_bytes_per_page); |
| |
| mvOsPrintf("spare bytes per page = %d\n", ppage->spare_bytes_per_page); |
| |
| mvOsPrintf("data bytes per partial page = %d\n", ppage->data_bytes_per_partial_page); |
| |
| mvOsPrintf("spare bytes per partial page = %d\n", ppage->spare_bytes_per_partial_page); |
| mvOsPrintf("pages per block = %d\n", ppage->pages_per_block); |
| mvOsPrintf("blocks per unit = %d\n", ppage->blocks_per_lun); |
| mvOsPrintf("Number of logical units (LUN) per chip enable = %d\n", ppage->luns_per_ce); |
| mvOsPrintf("Number of address cycles = %d\n", ppage->num_addr_cycles); |
| mvOsPrintf("Number of bits per cell (1 = SLC; >1= MLC) = %d\n", ppage->bit_per_cell); |
| mvOsPrintf("Bad blocks maximum per unit= %d\n", ppage->max_bad_blocks_per_lun); |
| mvOsPrintf("block endurance = %d\n", ppage->block_endurance); |
| mvOsPrintf("Guaranteed valid blocks at beginning of target = %d\n", ppage->guarenteed_valid_blocks); |
| |
| /* Block endurance for guaranteed valid blocks */ |
| mvOsPrintf("Block endurance for guaranteed valid blocks = %d\n", ppage->guarenteed_valid_blocks); |
| mvOsPrintf("Number of programs per page = %d\n", ppage->num_programs_per_page); |
| mvOsPrintf("Partial programming attributes = %d\n", ppage->partial_prog_attr); |
| mvOsPrintf("Number of bits ECC bits = %d\n", ppage->num_ECC_bits); |
| mvOsPrintf("Number of interleaved address bits = %d\n", ppage->num_interleaved_addr_bits); |
| mvOsPrintf("Interleaved operation attributes = %d\n", ppage->interleaved_op_attr); |
| } |