From 2c13362d8485b5713c4eecb4b71fa4c2830afb7d Mon Sep 17 00:00:00 2001 From: Md Sadre Alam Date: Wed, 9 Oct 2019 16:02:20 +0530 Subject: [PATCH] ipq5018: Enable support for serial nand in qpic This change will add support for serial nand. QPIC-2.1.1 supports parallel nand as well as serial nand. QPIC will operate either in parallel configuration or serial nand. Both can't work together. This change will support initially four serial nand parts. MT29F1G01ABBFDWB-IT (Micron-0x2C,0x15, 2K + 128) GD5F1GQ4RE9IG (Giga Device-0xC8,0xC1, 2K + 128) GD5F2GQ5REYIH (Giga Device-0xC8,0x22, 2K + 64) GD5F1GQ4RE9IH (Giga Device-0xC8, 0xC9, 2K + 64) Device Internal ECC is disabled for all three devices. This change will enabele QPIC ECC engine. For MT29F1G01ABBFDWB-IT 4-bit ECC as well 8-bit ECC will be supported. For GD5F1GQ4RE9IG 4-bit ECC as well 8-bit ECC will be supported. For GD5F2GQ5REYIH only 4-bit ECC will be supported due to 64-bytes spare. For GD5F1GQ4RE9IH only 4-bit ECC will be supported due to 64-bytes spare. Change-Id: I3f38f9c76b7bb235bb335a481fbc42ae1bd00395 Signed-off-by: Md Sadre Alam --- arch/arm/dts/ipq5018-emulation.dts | 5 + arch/arm/dts/ipq5018-soc.dtsi | 51 ++ .../include/asm/arch-qca-common/qpic_nand.h | 245 +++++- board/qca/arm/ipq5018/ipq5018.c | 9 + board/qca/arm/ipq5018/ipq5018.h | 10 + drivers/mtd/nand/qpic_nand.c | 785 +++++++++++++++++- include/configs/ipq5018.h | 4 + 7 files changed, 1069 insertions(+), 40 deletions(-) diff --git a/arch/arm/dts/ipq5018-emulation.dts b/arch/arm/dts/ipq5018-emulation.dts index d0b1b05cb2..5009210dd6 100644 --- a/arch/arm/dts/ipq5018-emulation.dts +++ b/arch/arm/dts/ipq5018-emulation.dts @@ -28,6 +28,11 @@ compatible = "qcom,sdhci-msm"; }; + nand: nand-controller@79B0000 { + status = "ok"; + nand_gpio {}; + }; + timer { gpt_freq_hz = <240000>; }; diff --git a/arch/arm/dts/ipq5018-soc.dtsi b/arch/arm/dts/ipq5018-soc.dtsi index b90548dc31..483fe38773 100644 --- a/arch/arm/dts/ipq5018-soc.dtsi +++ b/arch/arm/dts/ipq5018-soc.dtsi @@ -64,4 +64,55 @@ spi_gpio {}; }; + nand: nand-controller@79B0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,qpic-nand-v2.1.1"; + reg = <0x79B0000 0x10000>; + + nand_gpio { + qspi_data0 { + gpio = <7>; + func = <2>; + pull = ; + drvstr = ; + oe = ; + }; + qspi_data1 { + gpio = <6>; + func = <2>; + pull = ; + drvstr = ; + oe = ; + }; + qspi_data2 { + gpio = <5>; + func = <2>; + pull = ; + drvstr = ; + oe = ; + }; + qspi_data3 { + gpio = <4>; + func = <2>; + pull = ; + drvstr = ; + oe = ; + }; + qspi_cs_n { + gpio = <8>; + func = <2>; + pull = ; + drvstr = ; + oe = ; + }; + qspi_clk { + gpio = <9>; + func = <2>; + pull = ; + drvstr = ; + oe = ; + }; + }; + }; }; diff --git a/arch/arm/include/asm/arch-qca-common/qpic_nand.h b/arch/arm/include/asm/arch-qca-common/qpic_nand.h index f75145df65..5a802c3f23 100644 --- a/arch/arm/include/asm/arch-qca-common/qpic_nand.h +++ b/arch/arm/include/asm/arch-qca-common/qpic_nand.h @@ -94,11 +94,200 @@ #define NAND_EBI2_ECC_BUF_CFG NAND_REG(0x00F0) #define NAND_HW_INFO NAND_REG(0x00FC) #define NAND_FLASH_BUFFER NAND_REG(0x0100) +#define NAND_FLASH_FEATURES NAND_REG(0x0F64) #define QPIC_NAND_CTRL NAND_REG(0x0F00) #define QPIC_NAND_DEBUG NAND_REG(0x0F0C) +/* Additional Register set for Serial NAND */ +#define NAND_AUTO_STATUS_EN NAND_REG(0x002C) +#define NAND_VERSION NAND_REG(0x4F08) +#define SPI_NAND_DEV_CMD0 NAND_REG(0x70A0) +#define SPI_NAND_DEV_CMD1 NAND_REG(0x70A4) +#define SPI_NAND_DEV_CMD2 NAND_REG(0x70A8) +#define SPI_NAND_DEV_CMD3 NAND_REG(0x70D0) +#define NAND_FLASH_DEV_CMD_VLD NAND_REG(0x70AC) +#define SPI_NAND_DEV_CMD7 NAND_REG(0x70B0) +#define SPI_NAND_DEV_CMD8 NAND_REG(0x70B4) +#define SPI_NAND_DEV_CMD9 NAND_REG(0x70B8) +#define NAND_FLASH_SPI_CFG NAND_REG(0x70C0) +#define NAND_SPI_NUM_ADDR_CYCLES NAND_REG(0x70C4) +#define NAND_SPI_BUSY_CHECK_WAIT_CNT NAND_REG(0x70C8) + +/* Register mask & shift value used in SPI transfer mode */ +#define SPI_TRANSFER_MODE_1X 0x1 +#define SPI_TRANSFER_MODE_4X 0x3 +/* These value as per HPG , these value as per 2K device*/ +#define SPI_NAND_DEVn_CFG0 0x1A5408D0 +#define SPI_NAND_DEVn_CFG1 0x08287440 +#define SPI_NAND_DEVn_CFG1_RESET 0x087476B1 +/* value for below register according to HPG : 0x42040702 for reset + * and 0x42040700 for reset disable + */ +#define SPI_NAND_DEVn_ECC_CFG 0x42040702 +#define SPI_NAND_DEVn_ECC_CFG_RST_DIS 0x42040700 +#define FLASH_DEV_CMD_VLD 0x0000000D +/* These Value as per HPG */ +#define NAND_FLASH_DEV_CMD0_VAL 0x1080D8D8 +#define NAND_FLASH_DEV_CMD1_VAL 0xF00F3000 +#define NAND_FLASH_DEV_CMD2_VAL 0xF0FF709F +#define NAND_FLASH_DEV_CMD3_VAL 0x3F310015 +/* For Micron NAND_FLASH_DEV_CMD3_VAL value should + * be 0x3F300015 + */ +#define NAND_FLASH_DEV_CMD7_VAL 0x04061F0F +#define NAND_FLASH_DEV_CMD7_WE 0x60000 +#define NAND_FLASH_DEV_CMD7_WD 0x40000000 +#define NAND_FLASH_DEV_CMD7_SET_FTR 0x1F00 +#define NAND_FLASH_DEV_CMD7_GET_FTR 0x0F +#define SPI_BUSY_CHECK_WAIT_CNT 0x00000010 +#define SPI_CFG_VAL 0x1924C00D +#define SPI_LOAD_CLK_CNTR_INIT_EN (1 << 28) +#define SPI_NUM_ADDR_CYCLES 0x000DA4DB +#define NAND_FLASH_SET_FEATURE_MASK 0xB800000E +#define NAND_FLASH_GET_FEATURE_MASK 0x3800000E +#define QPIC_HARDWARE_VERSION_2_0 0x20000000 +#define NAND_FLASH_STATUS_MASK 0xC +#define QPIC_SERIAL_ERROR 517 +#define QPIC_SPI_SET_FEATURE (1 << 31) +#define QPIC_SPI_GET_FEATURE ~(1 << 31) +#define QPIC_SPI_WP_SET (1 << 28) +#define QPIC_SPI_HOLD_SET (1 << 27) +#define QPIC_SPI_TRANSFER_MODE_X1 (1 << 29) +#define QPIC_SPI_TRANSFER_MODE_X4 (3 << 29) +#define QPIC_SPI_BOOST_MODE (1 << 11) +#define QPIC_SPI_NAND_CTRL_VAL 0x341 +#define QPIC_SPI_NAND_AUTO_STATUS_VAL 0x003F003F +#define QPIC_NAND_FLASH_CMD_WE_VAL 0XB800000F +#define QPIC_NAND_FLASH_CMD_WD_VAL 0x3800000F +#define WR_EN 0x1 +#define WR_DIS 0x0 + +/* According to GigaDevice data sheet Block Protection Register is: + * ____________________________________________ + * | | | | | | | | | + * |BRWD |RSVD| BP2| BP1| BP0| INV | CMP |RSVD | + * | | | | | | | | | + * |______|____|____|____|____|_____|_____|_____| + * + * NOTE: RSVD = Reserved. + * + * After power-up the device is in "locked" state i.e feature bits + * BP0, BP1, BP2 are set to 1. ENV, CMP, BRWD are set to 0. + * When BRWD is set to 1 and WP# is LOW i.e 0, none of the writable + * protection feature bits can be set. + * When an ERASE command is issued to a locked block, the erase failure, + * 04H, is returned. + * + * With CMP = X, INV = X, BP2 = 0, BP1 = 0, BP0 = 0 : There will be no + * block protection functionality. + * + * When WP# is not LOW, user can issue bellows commands to alter the + * protection. + * + * Issue SET FEATURES register write (1FH) + * Issue the feature bit address (A0h) + */ +#define FLASH_SPI_NAND_BLK_PROCT_ADDR 0xA0 +#define FLASH_SPI_NAND_BLK_PROCT_DISABLE 0x00 +#define FLASH_SPI_NAND_BLK_PROCT_ENABLE 0x78 +/* According to GigaDevice data sheet Feature Register is: + * _________________________________________________ + * | | | | | | | | | + * |OTP-PRT|OTP_EN| RSVD|ECC-EN|RSVD|RSVD |RSVD |QE | + * | | | | | | | | | + * |_______|______|_____|______|____|_____|_____|____| + * + * + * NOTE : When a feature is set, it remains active until the + * device is power cycled or the feature is written to.once + * the device is set, it remains set, even if a RESET (FFH) + * command is issued. + * + * OTP-PRT = X , OTP_EN = 0 : Normal Operation + * OTP-PRT = 0, OTP_EN = 1 : Access OTP region, read and program data. + * + * ECC-EN : ECC is enabled after device power up, so the default + * READ and PROGRAM commands operate with internal ECC in the “active” + * state. To enable/disable ECC, perform the following command sequence: + * + * 1) Issue the SET FEATURES command (1FH). + * 2) Set the feature bit ECC_EN as you want: + * a) To enable ECC, Set ECC_EN to 1. + * b) To disable ECC, Clear ECC_EN to 0. + * + * NOTE: For this device GD5F1GQ4xExxG + * --> Internal ECC Off (ECC_EN=0): + * 2048-Byte+128-Byte Full Access. + * + * --> Internal ECC On (ECC_EN=1, default): + * Program: 2048-Byte+64-Byte. + * Read: 2048-Byte+128-Byte. + * + * QE : If QE is enabled, the quad IO operations can be executed. + * + */ +#define FLASH_SPI_NAND_FR_ADDR 0xB0 +#define FLASH_SPI_NAND_FR_ECC_ENABLE (1 << 4) +#define FLASH_SPI_NAND_FR_QUAD_ENABLE 0x1 +/* According to GigaDevice data sheet Status Register(0xC0) is: + * _________________________________________________ + * | | | | | | | | | + * |RSVD |RSVD |ECCS1|ECCS0|P-FAIL|E-FAIL|WEL |OIP | + * | | | | | | | | | + * |______|______|_____|_____|_____ |______|____|____| + * + * + * NOTE: RSVD = Reserved. + * + * P-FAIL : This bit indicates that a program failure has occurred + * (P_FAIL set to 1). It will also be set if the user attempts to + * program an invalid address or a protected region, including + * the OTP area. + * + * E-FAIL : This bit indicates that an erase failure has occurred + * (E_FAIL set to 1). It will also be set if the user attempts to + * erase a locked region. + * + * WEL : This bit indicates the current status of the write enable + * latch (WEL) and must be set (WEL = 1), prior to issuing a + * PROGRAM EXECUTE or BLOCK ERASE command. It is set by issuing the + * WRITE ENABLE command. WEL can also be disabled (WEL = 0), by issuing + * the WRITE DISABLE command. + * + * OIP : This bit is set (OIP = 1 ) when a PROGRAM EXECUTE, PAGE READ, + * BLOCK ERASE, or RESET command is executing, indicating the device + * is busy. When the bit is 0, the interface is in the ready state. + * + * ECC Status : ECCS and ECCSE are set to 00b either following a RESET, + * or at the beginning of the READ.ECCS and ECCSE are invalid if internal + * ECC is disabled (via a SET FEATURES command to reset ECC_EN to 0). + * + * NOTE: After power-on RESET, ECC status is set to reflect the contents + * of block 0, page 0. + */ +#define FLASH_SPI_NAND_SR_ADDR 0xC0 +#define FLASH_SPI_NAND_SR_DATA 0x00 + +/* According to GigaDevice data sheet Feature Register(0xD0) is: + * _________________________________________________ + * | | | | | | | | | + * |RSVD |DS-S1|DS-S0|RSVD |RSVD |RSVD |RSVD |RSVD| + * | | | | | | | | | + * |______|_____|_____|_____|______|______|_____|____| + * + * DS-S1 = 0 , DS-S0 = 0 : Drive strength is 50% + * DS-S1 = 0 , DS-S0 = 1 : Drive strength is 25% + * DS-S1 = 1 , DS-S0 = 0 : Drive strength is 75% + * DS-S1 = 1 , DS-S0 = 1 : Drive strength is 100% + * + * 00 is the default data byte value for Output Driver Register after power-up + */ +#define FLASH_SPI_NAND_FR_DS_ADDR 0xD0 +#define FLASH_SPI_NAND_FR_DS_DATA 0x00 + /* NANDc registers used during BAM transfer */ #define NAND_READ_LOCATION_n(n) (NAND_REG(0xF20) + 4 * (n)) +#define NAND_READ_LOCATION_LAST_CW_n(n) (NAND_REG(0xF40) + 4 * (n)) #define NAND_RD_LOC_LAST_BIT(x) ((x) << 31) #define NAND_RD_LOC_SIZE(x) ((x) << 16) #define NAND_RD_LOC_OFFSET(x) ((x) << 0) @@ -151,6 +340,23 @@ #define NAND_CMD_BLOCK_ERASE 0x3A #define NAND_CMD_FETCH_ID 0x0B #define NAND_CMD_RESET_DEVICE 0x0D +#define NAND_CMD_SET_FEATURE 0x1F +#define NAND_CMD_GET_FEATURE 0x0F +#define NAND_CMD_ACC_FEATURE 0x0E +/* Serial NAND Device command */ +#define SERIAL_NAND_CMD_READ_FROM_CACHE_X4 0x6B +#define SERIAL_NAND_CMD_READ_FROM_CACHE_DUAL_IO 0xBB +#define SERIAL_NAND_CMD_READ_FROM_CACHE_QUAD_IO 0xEB +#define SERIAL_NAND_CMD_READ_ID 0x9F +#define SERIAL_NAND_CMD_PROGRAM_LOAD 0x02 +#define SERIAL_NAND_CMD_PROGRAM_LOAD_X4 0x32 +#define SERIAL_NAND_CMD_PROGRAM_EXECUTE 0x10 +#define SERIAL_NAND_CMD_PROGRAM_LOAD_RND_DATA 0x84 +#define SERIAL_NAND_CMD_PROGRAM_LOAD_RND_DATA_X4 0xC4 /* Or 0x34 */ +#define SERIAL_NAND_CMD_PROGRAM_LOAD_QUAD_IO 0x72 +#define SERIAL_NAND_CMD_BLOCK_ERASE 0xD8 +#define SERIAL_NAND_CMD_RESET 0xFF + /* NAND Status errors */ #define NAND_FLASH_MPU_ERR (1 << 8) #define NAND_FLASH_TIMEOUT_ERR (1 << 6) @@ -170,6 +376,7 @@ #define DATA_CONSUMER_PIPE_INDEX 0 #define DATA_PRODUCER_PIPE_INDEX 1 #define CMD_PIPE_INDEX 2 +#define BAM_STATUS_PIPE_INDEX 3 /* Define BAM pipe lock groups for NANDc*/ #define P_LOCK_GROUP_0 0 @@ -238,11 +445,13 @@ #define DATA_CONSUMER_PIPE 0 #define DATA_PRODUCER_PIPE 1 #define CMD_PIPE 2 +#define NAND_BAM_STATUS_PIPE 3 /* NANDc BAM pipe groups */ #define DATA_PRODUCER_PIPE_GRP 0 #define DATA_CONSUMER_PIPE_GRP 0 #define CMD_PIPE_GRP 1 +#define NAND_BAM_STATUS_PIPE_GRP 2 /* NANDc EE */ #define QPIC_NAND_EE 0 @@ -252,6 +461,7 @@ /* Register: NAND_CTRL */ #define BAM_MODE_EN 0x1 +#define NANDC_READ_DELAY_COUNTER_VAL 0x340 /* Register: NAND_DEBUG */ #define BAM_MODE_BIT_RESET (1 << 31) @@ -277,6 +487,7 @@ #define QPIC_BAM_DATA_FIFO_SIZE 64 #define QPIC_BAM_CMD_FIFO_SIZE 64 +#define QPIC_BAM_STATUS_FIFO_SIZE 64 #define QPIC_MAX_ONFI_MODES 4 #define QPIC_NUM_XFER_STEPS 7 @@ -284,7 +495,7 @@ enum qpic_verion{ QCA_QPIC_V1_4_20, QCA_QPIC_V1_5_20, - + QCA_QPIC_V2_1_1, }; @@ -311,6 +522,28 @@ enum nand_cfg_value NAND_CFG, }; +/* Structure for Serial nand parameter */ +struct qpic_serial_nand_params { + u8 id[4]; + u16 page_size; + u16 pgs_per_blk; + u32 spare_size; + u32 erase_blk_size; + u16 no_of_blocks; + u32 density; + u32 otp_region; + u8 no_of_addr_cycle; + u8 no_of_dies; + u8 num_bits_ecc_correctability; + u8 timing_mode_support; + bool quad_mode; + bool check_quad_config; + int prev_die_id; + u8 protec_bpx; + u64 pages_per_die; + const char *name; +}; + struct onfi_param_page { uint32_t signature; @@ -396,9 +629,15 @@ struct qpic_nand_bam_pipes unsigned read_pipe; unsigned write_pipe; unsigned cmd_pipe; +#if defined(QPIC_SERIAL) && defined(MULTI_PAGE_READ) + unsigned status_pipe; +#endif uint8_t read_pipe_grp; uint8_t write_pipe_grp; uint8_t cmd_pipe_grp; +#if defined(QPIC_SERIAL) && defined(MULTI_PAGE_READ) + uint8_t status_pipe_grp; +#endif }; /* Structure to define the initial nand config */ @@ -442,6 +681,10 @@ struct qpic_nand_dev { uint32_t cfg0_raw; uint32_t cfg1_raw; uint32_t ecc_bch_cfg; +#ifdef CONFIG_QPIC_SERIAL + bool quad_mode; + bool check_quad_config; +#endif unsigned oob_per_page; unsigned char *buffers; unsigned char *pad_dat; diff --git a/board/qca/arm/ipq5018/ipq5018.c b/board/qca/arm/ipq5018/ipq5018.c index 90d4ce3981..37aa206e00 100644 --- a/board/qca/arm/ipq5018/ipq5018.c +++ b/board/qca/arm/ipq5018/ipq5018.c @@ -290,8 +290,17 @@ void reset_crashdump(void) return; } +void qpic_clk_enbale(void) +{ + writel(QPIC_CBCR_VAL, GCC_QPIC_CBCR_ADDR); + writel(0x1, GCC_QPIC_AHB_CBCR_ADDR); + writel(0x1, GCC_QPIC_IO_MACRO_CBCR); +} + void board_nand_init(void) { + qpic_nand_init(); + #ifdef CONFIG_QCA_SPI int gpio_node; gpio_node = fdt_path_offset(gd->fdt_blob, "/spi/spi_gpio"); diff --git a/board/qca/arm/ipq5018/ipq5018.h b/board/qca/arm/ipq5018/ipq5018.h index a220312d94..722a81d8a9 100644 --- a/board/qca/arm/ipq5018/ipq5018.h +++ b/board/qca/arm/ipq5018/ipq5018.h @@ -35,6 +35,15 @@ #define GCC_SDCC1_AHB_CBCR 0x0184201C #define GCC_SDCC1_MISC 0x01842020 +/* + * GCC-QPIC Registers + */ +#define GCC_QPIC_IO_MACRO_CBCR 0x0185701C +#define GCC_QPIC_CBCR_ADDR 0x01857020 +#define GCC_QPIC_AHB_CBCR_ADDR 0x01857024 +#define GCC_QPIC_SLEEP_CBCR 0x01857028 +#define QPIC_CBCR_VAL 0x80004FF1 + /* UART 1 */ #define GCC_BLSP1_UART1_BCR 0x01802038 #define GCC_BLSP1_UART1_APPS_CBCR 0x0180203C @@ -118,6 +127,7 @@ struct smem_ram_ptable { int smem_ram_ptable_init(struct smem_ram_ptable *smem_ram_ptable); void reset_crashdump(void); void reset_board(void); +void qpic_clk_enbale(void); typedef enum { SMEM_SPINLOCK_ARRAY = 7, diff --git a/drivers/mtd/nand/qpic_nand.c b/drivers/mtd/nand/qpic_nand.c index 09029388b2..a8879aad32 100644 --- a/drivers/mtd/nand/qpic_nand.c +++ b/drivers/mtd/nand/qpic_nand.c @@ -48,6 +48,78 @@ typedef unsigned long addr_t; static uint32_t hw_ver; +#ifdef CONFIG_QPIC_SERIAL +static struct qpic_serial_nand_params qpic_serial_nand_tbl[] = { + { + .id = { 0xc8, 0xc1 }, + .page_size = 2048, + .erase_blk_size = 0x00020000, + .pgs_per_blk = 64, + .no_of_blocks = 1024, + .spare_size = 128, + .density = 0x08000000, + .otp_region = 0x2000, + .no_of_addr_cycle = 0x3, + .num_bits_ecc_correctability = 8, + .timing_mode_support = 0, + .quad_mode = true, + .check_quad_config = true, + .name = "GD5F1GQ4RE9IG", + }, + { + .id = { 0xc8, 0xc9 }, + .page_size = 2048, + .erase_blk_size = 0x00020000, + .pgs_per_blk = 64, + .no_of_blocks = 1024, + .spare_size = 64, + .density = 0x08000000, + .otp_region = 0x2000, + .no_of_addr_cycle = 0x3, + .num_bits_ecc_correctability = 4, + .timing_mode_support = 0, + .quad_mode = true, + .check_quad_config = true, + .name = "GD5F1GQ4RE9IH", + }, + { + .id = { 0xc8, 0x22 }, + .page_size = 2048, + .erase_blk_size = 0x00020000, + .pgs_per_blk = 64, + .no_of_blocks = 2048, + .spare_size = 64, + .density = 0x10000000, + .otp_region = 0x2000, + .no_of_addr_cycle = 0x3, + .num_bits_ecc_correctability = 4, + .timing_mode_support = 0, + .quad_mode = true, + .check_quad_config = true, + .name = "GD5F2GQ5REYIH", + }, + { + .id = { 0x2c, 0x15 }, + .page_size = 2048, + .erase_blk_size = 0x00020000, + .pgs_per_blk = 64, + .no_of_blocks = 1024, + .spare_size = 128, + .density = 0x08000000, + .otp_region = 0x5000, + .no_of_addr_cycle = 0x3, + .num_bits_ecc_correctability = 8, + .timing_mode_support = 0, + .quad_mode = true, + .check_quad_config = false, + .name = "MT29F1G01ABBFDWB-IT", + }, +}; +struct qpic_serial_nand_params *serial_params; +#define MICRON_DEVICE_ID 0x152c152c +#define CMD3_MASK 0xfff0ffff +#endif + struct cmd_element ce_array[100] __attribute__ ((aligned(CONFIG_SYS_CACHELINE_SIZE))); struct cmd_element ce_read_array[20] @@ -57,6 +129,8 @@ struct bam_desc qpic_cmd_desc_fifo[QPIC_BAM_CMD_FIFO_SIZE] __attribute__ ((aligned(CONFIG_SYS_CACHELINE_SIZE))); struct bam_desc qpic_data_desc_fifo[QPIC_BAM_DATA_FIFO_SIZE] __attribute__ ((aligned(CONFIG_SYS_CACHELINE_SIZE))); +struct bam_desc qpic_status_desc_fifo[QPIC_BAM_STATUS_FIFO_SIZE] + __attribute__ ((aligned(CONFIG_SYS_CACHELINE_SIZE))); static struct bam_instance bam; struct nand_ecclayout fake_ecc_layout; @@ -77,16 +151,24 @@ qpic_nand_read_page(struct mtd_info *mtd, uint32_t page, static const struct udevice_id qpic_ver_ids[] = { { .compatible = "qcom,qpic-nand.1.4.20", .data = QCA_QPIC_V1_4_20 }, { .compatible = "qcom,qpic-nand.1.5.20", .data = QCA_QPIC_V1_5_20 }, + { .compatible = "qcom,qpic-nand-v2.1.1", .data = QCA_QPIC_V2_1_1}, { }, }; static uint32_t qpic_onfi_mode_to_xfer_steps[QPIC_MAX_ONFI_MODES][QPIC_NUM_XFER_STEPS] = { +#ifdef CONFIG_QPIC_SERIAL /* Mode 0 */ + { + 0x00e00080, 0x49f04998, 0x8de08d80, 0xc000c000, + 0xc000c000, 0xc000c000, 0xc000c000, + }, +#else { 0x04e00480, 0x59f05998, 0x89e08980, 0xd000d000, 0xc000c000, 0xc000c000, 0xc000c000, }, +#endif /* Mode 1 */ { 0x00e00080, 0x49f04d99, 0x85e08580, 0xd000d000, @@ -254,17 +336,20 @@ qpic_nand_fetch_id(struct mtd_info *mtd) uint32_t flash_cmd = NAND_CMD_FETCH_ID; uint32_t exec_cmd = 1; int nand_ret = NANDC_RESULT_SUCCESS; - uint32_t vld; + uint32_t vld = NAND_CMD_VALID_BASE; uint32_t cmd_vld = NAND_DEV_CMD_VLD_V1_4_20; +#ifdef CONFIG_QPIC_SERIAL + flash_cmd |= QPIC_SPI_WP_SET | QPIC_SPI_HOLD_SET | + QPIC_SPI_TRANSFER_MODE_X1; + vld = FLASH_DEV_CMD_VLD; +#endif /* Issue the Fetch id command to the NANDc */ bam_add_cmd_element(cmd_list_ptr, NAND_FLASH_CMD, (uint32_t)flash_cmd, - CE_WRITE_TYPE); + CE_WRITE_TYPE); cmd_list_ptr++; - vld = NAND_CMD_VALID_BASE; - - if (hw_ver == QCA_QPIC_V1_5_20) + if (hw_ver == QCA_QPIC_V1_5_20 || hw_ver == QCA_QPIC_V2_1_1) cmd_vld = NAND_DEV_CMD_VLD_V1_5_20; bam_add_cmd_element(cmd_list_ptr, cmd_vld, (uint32_t)vld, @@ -288,9 +373,6 @@ qpic_nand_fetch_id(struct mtd_info *mtd) num_desc++; qpic_nand_wait_for_cmd_exec(num_desc); - cmd_list_ptr_start = ce_array; - cmd_list_ptr = ce_array; - /* Read the status register */ status = qpic_nand_read_reg(NAND_FLASH_STATUS, 0); @@ -349,7 +431,15 @@ qpic_bam_init(struct qpic_nand_init_config *config) bam.pipe[CMD_PIPE_INDEX].fifo.size = QPIC_BAM_CMD_FIFO_SIZE; bam.pipe[CMD_PIPE_INDEX].fifo.head = qpic_cmd_desc_fifo; bam.pipe[CMD_PIPE_INDEX].lock_grp = config->pipes.cmd_pipe_grp; - +#if defined(CONFIG_QPIC_SERIAL) && defined(MULTI_PAGE_READ) + /* Set Status pipe params. */ + bam.pipe[BAM_STATUS_PIPE_INDEX].pipe_num = config->pipes.status_pipe; + /* System consumer */ + bam.pipe[BAM_STATUS_PIPE_INDEX].trans_type = BAM2SYS; + bam.pipe[BAM_STATUS_PIPE_INDEX].fifo.size = QPIC_BAM_STATUS_FIFO_SIZE; + bam.pipe[BAM_STATUS_PIPE_INDEX].fifo.head = qpic_status_desc_fifo; + bam.pipe[BAM_STATUS_PIPE_INDEX].lock_grp = config->pipes.status_pipe_grp; +#endif /* Programs the threshold for BAM transfer * When this threshold is reached, BAM signals the peripheral via the * pipe_bytes_available interface. @@ -408,15 +498,32 @@ qpic_bam_init(struct qpic_nand_init_config *config) bam_ret = NANDC_RESULT_FAILURE; goto qpic_nand_bam_init_error; } +#if defined(CONFIG_QPIC_SERIAL) && defined(MULTI_PAGE_READ) + /* Initialize BAM QPIC status pipe */ + bam_sys_pipe_init(&bam, BAM_STATUS_PIPE_INDEX); + /* Init status fifo */ + bam_ret = bam_pipe_fifo_init(&bam, bam.pipe[BAM_STATUS_PIPE_INDEX].pipe_num); + + if (bam_ret) { + printf("QPIC:NANDc BAM STATUS FIFO init error\n"); + bam_ret = NANDC_RESULT_FAILURE; + goto qpic_nand_bam_init_error; + } +#endif /* * Once BAM_MODE_EN bit is set then QPIC_NAND_CTRL register * should be written with BAM instead of writel. * Check if BAM_MODE_EN is already set by bootloader and write only * if this bit is not set. */ - if (!(readl(QPIC_NAND_CTRL) & BAM_MODE_EN)) - writel(BAM_MODE_EN, QPIC_NAND_CTRL); + if (!(readl(QPIC_NAND_CTRL) & BAM_MODE_EN)) { +#ifdef CONFIG_QPIC_SERIAL + writel(BAM_MODE_EN | NANDC_READ_DELAY_COUNTER_VAL, QPIC_NAND_CTRL); +#else + writel(BAM_MODE_EN , QPIC_NAND_CTRL); +#endif + } qpic_nand_bam_init_error: return bam_ret; @@ -580,6 +687,7 @@ qpic_nand_onfi_probe_cleanup(uint32_t vld, uint32_t dev_cmd1) qpic_nand_wait_for_cmd_exec(1); } +#ifndef CONFIG_QPIC_SERIAL static void qpic_config_timing_parameters(struct mtd_info *mtd) { @@ -605,6 +713,40 @@ qpic_config_timing_parameters(struct mtd_info *mtd) writel(qpic_onfi_mode_to_xfer_steps[timing_mode][i], xfer_start + 4 * i); } +#endif + +#ifdef CONFIG_QPIC_SERIAL +static void qpic_serial_update_dev_params(struct mtd_info *mtd) +{ + struct qpic_nand_dev *dev = MTD_QPIC_NAND_DEV(mtd); + uint32_t ecc_bits; + + dev->page_size = serial_params->page_size; + mtd->writesize = dev->page_size; + dev->block_size = serial_params->pgs_per_blk * (dev->page_size); + mtd->erasesize = dev->block_size; + dev->num_blocks = serial_params->no_of_blocks; + dev->widebus = 0x0; + dev->density = serial_params->no_of_blocks * (dev->block_size); + mtd->size = dev->density; + dev->spare_size = serial_params->spare_size; + mtd->oobsize = dev->spare_size; + ecc_bits = serial_params->num_bits_ecc_correctability; + dev->num_pages_per_blk = serial_params->pgs_per_blk; + dev->num_pages_per_blk_mask = serial_params->pgs_per_blk - 1; + dev->timing_mode_support = serial_params->timing_mode_support; + dev->quad_mode = serial_params->quad_mode; + dev->check_quad_config = serial_params->check_quad_config; + + if (ecc_bits >= 8) + mtd->ecc_strength = 8; + else + mtd->ecc_strength = 4; + printf("Serial NAND device Manufature:%s\n",serial_params->name); + printf("Device Size:%d MiB, Page size:%d, Spare Size:%d\n", + (int)(dev->density >> 20), dev->page_size, mtd->oobsize); +} +#endif static int qpic_nand_onfi_save_params(struct mtd_info *mtd, @@ -651,6 +793,10 @@ qpic_nand_save_config(struct mtd_info *mtd) struct qpic_nand_dev *dev = MTD_QPIC_NAND_DEV(mtd); struct nand_chip *chip = MTD_NAND_CHIP(mtd); uint32_t qpic_oob_size; + uint32_t no_of_address_cycle = 5; + uint32_t disable_status_after_write = 0; + uint32_t recovery_cycle = 7; + uint32_t wr_rd_busy_gap = 2; /* Save Configurations */ dev->cws_per_page = dev->page_size >> NAND_CW_DIV_RIGHT_SHIFT; @@ -719,37 +865,41 @@ qpic_nand_save_config(struct mtd_info *mtd) */ dev->bad_blk_loc = dev->page_size - dev->cw_size * (dev->cws_per_page - 1) + 1; - +#ifdef CONFIG_QPIC_SERIAL + no_of_address_cycle = 3; + disable_status_after_write = 1; + recovery_cycle = 0; + wr_rd_busy_gap = 20; +#endif dev->cfg0 |= ((dev->cws_per_page - 1) << NAND_DEV0_CFG0_CW_PER_PAGE_SHIFT) /* 4/8 cw/pg for 2/4k */ |(DATA_BYTES_IN_IMG_PER_CW << NAND_DEV0_CFG0_UD_SIZE_BYTES_SHIFT) /* 516 user data bytes */ - |(5 << NAND_DEV0_CFG0_ADDR_CYCLE_SHIFT) /* 5 address cycles */ - |(0 << NAND_DEV0_CFG0_DIS_STS_AFTER_WR_SHIFT);/* Send read status cmd after each write. */ + |(no_of_address_cycle << NAND_DEV0_CFG0_ADDR_CYCLE_SHIFT) /* 5 address cycles */ + |(disable_status_after_write << NAND_DEV0_CFG0_DIS_STS_AFTER_WR_SHIFT);/* Send read status cmd after each write. */ - dev->cfg1 |= (7 << NAND_DEV0_CFG1_RECOVERY_CYCLES_SHIFT) /* 8 recovery cycles */ + dev->cfg1 |= (recovery_cycle << NAND_DEV0_CFG1_RECOVERY_CYCLES_SHIFT) /* 8 recovery cycles */ |(0 << NAND_DEV0_CFG1_CS_ACTIVE_BSY_SHIFT) /* Allow CS deassertion */ |(dev->bad_blk_loc << NAND_DEV0_CFG1_BAD_BLK_BYTE_NUM_SHIFT)/* Bad block marker location */ |(0 << NAND_DEV0_CFG1_BAD_BLK_IN_SPARE_SHIFT) /* Bad block in user data area */ - |(2 << NAND_DEV0_CFG1_WR_RD_BSY_GAP_SHIFT) /* 8 cycle tWB/tRB */ + |(wr_rd_busy_gap << NAND_DEV0_CFG1_WR_RD_BSY_GAP_SHIFT) /* 8 cycle tWB/tRB */ |(dev->widebus << NAND_DEV0_CFG1_WIDE_BUS_SHIFT); /* preserve wide flash flag */ dev->cfg0_raw = ((dev->cws_per_page- 1) << NAND_DEV0_CFG0_CW_PER_PAGE_SHIFT) - |(5 << NAND_DEV0_CFG0_ADDR_CYCLE_SHIFT) + |(no_of_address_cycle << NAND_DEV0_CFG0_ADDR_CYCLE_SHIFT) |(dev->cw_size << NAND_DEV0_CFG0_UD_SIZE_BYTES_SHIFT) //figure out the size of cw - | (1 << NAND_DEV0_CFG0_DIS_STS_AFTER_WR_SHIFT); + | (disable_status_after_write << NAND_DEV0_CFG0_DIS_STS_AFTER_WR_SHIFT); - dev->cfg1_raw = (7 << NAND_DEV0_CFG1_RECOVERY_CYCLES_SHIFT) + dev->cfg1_raw = (recovery_cycle << NAND_DEV0_CFG1_RECOVERY_CYCLES_SHIFT) | (0 << NAND_DEV0_CFG1_CS_ACTIVE_BSY_SHIFT) | (17 << NAND_DEV0_CFG1_BAD_BLK_BYTE_NUM_SHIFT) | (1 << NAND_DEV0_CFG1_BAD_BLK_IN_SPARE_SHIFT) - | (2 << NAND_DEV0_CFG1_WR_RD_BSY_GAP_SHIFT) + | (wr_rd_busy_gap << NAND_DEV0_CFG1_WR_RD_BSY_GAP_SHIFT) | (dev->widebus << NAND_DEV0_CFG1_WIDE_BUS_SHIFT) | 1 ; /* to disable reed solomon ecc..this feild is now read only. */ dev->ecc_bch_cfg |= (0 << NAND_DEV0_ECC_DISABLE_SHIFT) /* Enable ECC */ - | (0 << NAND_DEV0_ECC_SW_RESET_SHIFT) /* Put ECC core in op mode */ - | (DATA_BYTES_IN_IMG_PER_CW << - NAND_DEV0_ECC_NUM_DATA_BYTES) - | (1 << NAND_DEV0_ECC_FORCE_CLK_OPEN_SHIFT); /* Enable all clocks */ + | (0 << NAND_DEV0_ECC_SW_RESET_SHIFT) /* Put ECC core in op mode */ + | (DATA_BYTES_IN_IMG_PER_CW << NAND_DEV0_ECC_NUM_DATA_BYTES) + | (1 << NAND_DEV0_ECC_FORCE_CLK_OPEN_SHIFT); /* Enable all clocks */ /* * Safe to use a single instance global variable, @@ -764,6 +914,331 @@ qpic_nand_save_config(struct mtd_info *mtd) return 0; } +#ifdef CONFIG_QPIC_SERIAL +static int qpic_serial_get_feature(struct mtd_info *mtd, uint32_t ftr_addr) +{ + struct cmd_element *cmd_list_ptr = ce_array; + struct cmd_element *cmd_list_ptr_start = ce_array; + uint8_t num_desc = 0; + uint32_t status, nand_ret; + uint32_t exec_cmd = 1; + + uint32_t cmd_val = (QPIC_SPI_TRANSFER_MODE_X1 | QPIC_SPI_HOLD_SET | + QPIC_SPI_WP_SET | NAND_CMD_ACC_FEATURE); + + /* Set the feature address to NAND_ADDR0 register */ + bam_add_cmd_element(cmd_list_ptr, NAND_ADDR0, ftr_addr, + CE_WRITE_TYPE); + cmd_list_ptr++; + + /* Set the value 0x0 to NAND_ADDR1 register */ + bam_add_cmd_element(cmd_list_ptr, NAND_ADDR1, 0, + CE_WRITE_TYPE); + cmd_list_ptr++; + + /* First Clear the feature register to get the fresh feature value */ + bam_add_cmd_element(cmd_list_ptr, NAND_FLASH_FEATURES, 0, + CE_WRITE_TYPE); + cmd_list_ptr++; + + /* cmd_val = 0x3800000E + * bit-31 is clear means set feature + * bit-30-29 means x1 mode + * bit-28 is set , this is for wp pin + * wp# pin should be set to high then only we can get the feature + * bit-27 SPI_HOLD : this pin also should be high + */ + bam_add_cmd_element(cmd_list_ptr, NAND_FLASH_CMD, cmd_val, + CE_WRITE_TYPE); + cmd_list_ptr++; + + /* Execute the cmd */ + bam_add_cmd_element(cmd_list_ptr, NAND_EXEC_CMD, exec_cmd, + CE_WRITE_TYPE); + cmd_list_ptr++; + + /* Prepare the cmd desc for the above commands */ + bam_add_one_desc(&bam, CMD_PIPE_INDEX, + (unsigned char *)cmd_list_ptr_start, + ((uint32_t)cmd_list_ptr - (uint32_t)cmd_list_ptr_start), + BAM_DESC_NWD_FLAG | BAM_DESC_CMD_FLAG | + BAM_DESC_INT_FLAG); + + /* Keep track of the number of desc added. */ + num_desc++; + + qpic_nand_wait_for_cmd_exec(num_desc); + + status = qpic_nand_read_reg(NAND_FLASH_STATUS, 0); + + /* Check for errors */ + nand_ret = qpic_nand_check_status(mtd, status); + if (nand_ret) { + printf("%s : CMD status failed\n", __func__); + goto err; + } + /* read the feature register value and update in feature + * Feature value will get updated in [15:8] + */ + nand_ret = qpic_nand_read_reg(NAND_FLASH_FEATURES, 0); +#ifdef QPIC_DEBUG_SERIAL + printf("NAND Feature Register Addr:0x%02x and Val:0x%08x\n", + ftr_addr,nand_ret); +#endif +err: + return nand_ret; + +} + +static int qpic_serial_set_feature(struct mtd_info *mtd, uint32_t ftr_addr, + uint32_t ftr_val) +{ + struct cmd_element *cmd_list_ptr = ce_array; + struct cmd_element *cmd_list_ptr_start = ce_array; + uint8_t num_desc = 0; + uint32_t status, nand_ret; + + uint32_t cmd_val = (QPIC_SPI_SET_FEATURE | QPIC_SPI_WP_SET | + QPIC_SPI_HOLD_SET | QPIC_SPI_TRANSFER_MODE_X1 | + NAND_CMD_ACC_FEATURE); + + uint32_t exec_cmd = 1; + + /* set the feature value to NAND_FLASH_FEATURES feature register */ + bam_add_cmd_element(cmd_list_ptr, NAND_FLASH_FEATURES, ftr_val, + CE_WRITE_TYPE); + cmd_list_ptr++; + + /* Set the feature address to NAND_ADDR0 register */ + bam_add_cmd_element(cmd_list_ptr, NAND_ADDR0, ftr_addr, + CE_WRITE_TYPE); + cmd_list_ptr++; + + /* Set the value 0x0 to NAND_ADDR1 register */ + bam_add_cmd_element(cmd_list_ptr, NAND_ADDR1, 0, + CE_WRITE_TYPE); + cmd_list_ptr++; + + /* cmd_val = 0xB800000E + * bit-31 is set means set feature + * bit-30-29 means x1 mode + * bit-28 is set , this is for wp pin + * wp# pin should be set to high then only we can set the feature + * bit-27 SPI_HOLD : this pin also should be high + */ + bam_add_cmd_element(cmd_list_ptr, NAND_FLASH_CMD, cmd_val, + CE_WRITE_TYPE); + cmd_list_ptr++; + + /* Execute the cmd */ + bam_add_cmd_element(cmd_list_ptr, NAND_EXEC_CMD, exec_cmd, + CE_WRITE_TYPE); + cmd_list_ptr++; + + /* Prepare the cmd desc for the above commands */ + bam_add_one_desc(&bam, CMD_PIPE_INDEX, + (unsigned char *)cmd_list_ptr_start, + ((uint32_t)cmd_list_ptr - (uint32_t)cmd_list_ptr_start), + BAM_DESC_NWD_FLAG | BAM_DESC_CMD_FLAG | + BAM_DESC_INT_FLAG); + + /* Keep track of the number of desc added. */ + num_desc++; + + qpic_nand_wait_for_cmd_exec(num_desc); + + status = qpic_nand_read_reg(NAND_FLASH_STATUS, 0); + + /* Check for errors */ + nand_ret = qpic_nand_check_status(mtd, status); + if (nand_ret) { + printf("%s : CMD status failed\n", __func__); + goto err; + } +err: + return nand_ret; +} + +static int qpic_nand_read_id_serial(struct mtd_info *mtd) +{ + uint32_t nand_ret; + uint32_t serial_dev_id[2] = {0x0}; + int i; + struct qpic_nand_dev *dev = MTD_QPIC_NAND_DEV(mtd); + + nand_ret = qpic_nand_fetch_id(mtd); + if (!nand_ret) { + + serial_dev_id[0] = dev->id & 0x000000ff; + serial_dev_id[1] = (dev->id >> 8) & 0x000000ff; + + for (i = 0; i < ARRAY_SIZE(qpic_serial_nand_tbl); i++) { + serial_params = &qpic_serial_nand_tbl[i]; + if ((serial_params->id[0] == serial_dev_id[0]) && + (serial_params->id[1] == serial_dev_id[1])) { + printf("Serial Nand Device Found With ID : 0x%02x 0x%02x\n", + serial_dev_id[0],serial_dev_id[1]); + + /* Upadate device paramter as per device table */ + qpic_serial_update_dev_params(mtd); + + return nand_ret; + } + } + if (i == ARRAY_SIZE(qpic_serial_nand_tbl)) { + printf("%s : No serial Nand device found in table.\n", + __func__); + return -QPIC_SERIAL_ERROR; + } + } else { + printf("%s : Error in featching id from device\n",__func__); + goto id_err; + } +id_err: + return nand_ret; +} + +int qpic_spi_nand_config(struct mtd_info *mtd) +{ + uint32_t status = 0x0; + struct qpic_nand_dev *dev = MTD_QPIC_NAND_DEV(mtd); + uint32_t cmd3_val = NAND_FLASH_DEV_CMD3_VAL; + /* For micron device the READ_CACHE_SEQ command is different than + * Giga device. for Giga 0x31 and for Micron 0x30. + * so based on id update the command configuration register + * CMD3. + */ + if (dev->id == MICRON_DEVICE_ID) { + cmd3_val = (NAND_FLASH_DEV_CMD3_VAL & CMD3_MASK); + writel(cmd3_val, SPI_NAND_DEV_CMD3); + } + /* Get the block protection status*/ + status = qpic_serial_get_feature(mtd, FLASH_SPI_NAND_BLK_PROCT_ADDR); + if (status < 0) { + printf("%s : Error in getting feature.\n",__func__); + return status; + } + + if ((status >> 8) & FLASH_SPI_NAND_BLK_PROCT_ENABLE) { + printf("%s: Block protection is enabled\n",__func__); + printf("%s: Issuing set feature command to disable it.\n",__func__); + + status = qpic_serial_set_feature(mtd, FLASH_SPI_NAND_BLK_PROCT_ADDR, + FLASH_SPI_NAND_BLK_PROCT_DISABLE); + if (status < 0) { + printf("%s : Error in disabling block protection.\n",__func__); + return status; + } + /* After disabling the block protection again read the status + * i.e again call the get feature command to get the status + */ + status = qpic_serial_get_feature(mtd, FLASH_SPI_NAND_BLK_PROCT_ADDR); + if (status < 0) { + printf("%s : Error in getting feature.\n",__func__); + return status; + } + if ((status >> 8) & FLASH_SPI_NAND_BLK_PROCT_ENABLE) { + printf("%s : block protection still enabled.We can't erase a block\n", + __func__); + return -QPIC_SERIAL_ERROR; + } else + printf("%s : Block protection Disabled.\n",__func__); + } else + printf("%s: Block protection Disabled on Power on.\n",__func__); + + /* Get Internal ECC status */ + status = qpic_serial_get_feature(mtd, FLASH_SPI_NAND_FR_ADDR); + if (status < 0) { + printf("%s : Error in getting feature.\n",__func__); + return status; + } + + if ((status >> 8) & FLASH_SPI_NAND_FR_ECC_ENABLE) { + printf("%s : Internal ECC enabled, disabling internal ECC\n",__func__); + + status &= ~(FLASH_SPI_NAND_FR_ECC_ENABLE); + status = qpic_serial_set_feature(mtd, FLASH_SPI_NAND_FR_ADDR, + status); + + if (status < 0) { + printf("%s : Error in disabling internal ECC.\n",__func__); + return status; + } + /* again check internal ECC is disabled or not using get feature + * command + */ + status = qpic_serial_get_feature(mtd, FLASH_SPI_NAND_FR_ADDR); + if (status < 0) { + printf("%s : Error in getting feature.\n",__func__); + return status; + } + + if ((status >> 8) & FLASH_SPI_NAND_FR_ECC_ENABLE) { + pr_info("%s: Failed to disabled device internal ECC\n", + __func__); + return -QPIC_SERIAL_ERROR; + } else + printf("%s : Internal ECC disabled.\n",__func__); + } else + printf("%s : Internal ECC disabled on power on.\n",__func__); + + /* Enable QUAD mode if device supported. Check this condition only + * if dev->quad_mode = true , means device will support Quad mode + * else no need to check for Quad mode. + * For Micron device there is no quad config bit so no need to check + * quad config bit. + */ + /* Get QUAD bit status */ + if (!dev->check_quad_config) { + dev->quad_mode = true; + return 0; + } + + if (dev->quad_mode) { + + status = qpic_serial_get_feature(mtd, FLASH_SPI_NAND_FR_ADDR); + if (status < 0) { + printf("%s : Error in getting feature.\n",__func__); + return status; + } + + if (!((status >> 8) & FLASH_SPI_NAND_FR_QUAD_ENABLE)) { + printf("%s : Quad bit not enabled.\n",__func__); + printf("%s : Issuning set feature command to enable it.\n", + __func__); + + /* Enable quad bit */ + status = qpic_serial_set_feature(mtd, FLASH_SPI_NAND_FR_ADDR, + FLASH_SPI_NAND_FR_QUAD_ENABLE); + if (status < 0) { + printf("%s : Error in enabling Quad bit.\n",__func__); + return status; + } + /* Read status again to know wether Quad bit enabled or not */ + status = qpic_serial_get_feature(mtd, FLASH_SPI_NAND_FR_ADDR); + if (status < 0) { + printf("%s : Error in getting feature.\n",__func__); + return status; + } + + if (!((status >> 8) & FLASH_SPI_NAND_FR_QUAD_ENABLE)) { + printf("%s:Quad mode not enabled,so use x1 Mode.\n", + __func__); + dev->quad_mode = false; + return 0; + } else { + printf("%s: Quad mode enabled. using X4 mode\n",__func__); + return 0; + } + } else { + printf("%s: Quad mode enabled on Opwer on.\n",__func__); + return 0; + } + } + return 0; +} +#endif + /* Onfi probe should issue the following commands to the flash device: * 1. Read ID - with addr ONFI_READ_ID_ADDR. * This returns the ONFI ASCII string indicating support for ONFI. @@ -786,6 +1261,12 @@ qpic_nand_onfi_probe(struct mtd_info *mtd) struct onfi_param_page *param_page; int onfi_ret = NANDC_RESULT_SUCCESS; +#ifdef CONFIG_QPIC_SERIAL + uint32_t nand_ret; + nand_ret = qpic_nand_read_id_serial(mtd); + return nand_ret; +#endif + /* Allocate memory required to read the onfi param page */ buffer = (unsigned char*) malloc(ONFI_READ_PARAM_PAGE_BUFFER_SIZE); if (buffer == NULL) { @@ -891,8 +1372,77 @@ qpic_nand_onfi_probe_err: return onfi_ret; } -static int -qpic_nand_reset(struct mtd_info *mtd) +#ifdef CONFIG_QPIC_SERIAL +static void qpic_spi_init(struct mtd_info *mtd) +{ + uint32_t xfer_start = NAND_XFR_STEPS_V1_5_20; + int i; + + /* Enabel QSPI CLK*/ + qpic_clk_enbale(); + + /* Configure the NAND_FLASH_SPI_CFG to load the timer CLK_CNTR_INIT_VAL_VEC + * value, enable the LOAD_CLK_CNTR_INIT_EN bit and enable SPI_CFG mode. + */ + writel(0x0, NAND_FLASH_SPI_CFG); + + /* Make bit-28 of NAND_FLASH_SPI_CFG register to load + * CLK_CNTR_INIT_VAL_VEC into IO Macro clock generation + * registers is its not worked then, + * check with this val 0x1DB6C00D + */ + writel(SPI_CFG_VAL, NAND_FLASH_SPI_CFG); + /*Change LOAD_CLK_CNTR_INIT_EN to generate a pulse, + * with CLK_CNTR_INIT_VAL_VEC loaded and SPI_CFG enabled + * If not worked then, + * Check with this val 0xDB6C00D + */ + writel((SPI_CFG_VAL & ~SPI_LOAD_CLK_CNTR_INIT_EN), + NAND_FLASH_SPI_CFG); + + /* According to HPG Setting Xfer steps and spi_num_addr_cycles + * is part of initialization flow before reset.However these + * values differ from NAND part to part.sitting in QPIC layer + * we won't know which NAND we don't know which NAND is connected. + * So we are not following HPG init sequence.Instead we reset and + * read id of NAND,then based on NAND ID we get Xfer steps + * and spi_num_addr_cycles and configure them in this function.Since + * Xfer steps and spi_num_addr_cycles are required for read/write/erase + * functionality. + * + * NOTE: For now address cycle is same for Giga devices & Micron devices + * so we can configure no of addess cycle here only + * The NAND_FLASH_XFR_STEP register also fixed for both the devices so we + * can configure this register here only . later change this logic as per + * device + * + * NOTE: The XFER register value is now fixed as HPG. + * + */ + for (i = 0; i < QPIC_NUM_XFER_STEPS; i++) + writel(qpic_onfi_mode_to_xfer_steps[0][i], + xfer_start + 4 * i); + + writel(NAND_FLASH_DEV_CMD0_VAL, SPI_NAND_DEV_CMD0); + writel(NAND_FLASH_DEV_CMD1_VAL, SPI_NAND_DEV_CMD1); + writel(NAND_FLASH_DEV_CMD2_VAL, SPI_NAND_DEV_CMD2); + writel(NAND_FLASH_DEV_CMD3_VAL, SPI_NAND_DEV_CMD3); + writel(NAND_FLASH_DEV_CMD7_VAL, SPI_NAND_DEV_CMD7); + + /* NAND_DEV_CMD8 & NAND_DEV_CMD9 default value will be used for + * QSPI + */ + writel(FLASH_DEV_CMD_VLD, NAND_FLASH_DEV_CMD_VLD); + + /* No of address cycle is same for Giga device & Micron so + * configure no of address cycle now. + */ + writel(SPI_NUM_ADDR_CYCLES, NAND_SPI_NUM_ADDR_CYCLES); + + writel(SPI_BUSY_CHECK_WAIT_CNT, NAND_SPI_BUSY_CHECK_WAIT_CNT); +} +#endif +static int qpic_nand_reset(struct mtd_info *mtd) { struct cmd_element *cmd_list_ptr = ce_array; struct cmd_element *cmd_list_ptr_start = ce_array; @@ -901,6 +1451,33 @@ qpic_nand_reset(struct mtd_info *mtd) uint32_t exec_cmd = 1; uint32_t flash_cmd = NAND_CMD_RESET_DEVICE; +#ifdef CONFIG_QPIC_SERIAL + flash_cmd |= (QPIC_SPI_WP_SET | QPIC_SPI_HOLD_SET | QPIC_SPI_TRANSFER_MODE_X1); + uint32_t cfg0 = SPI_NAND_DEVn_CFG0 & 0xff00f0; + uint32_t cfg1 = SPI_NAND_DEVn_CFG1_RESET; + uint32_t ecc_cfg = ((SPI_NAND_DEVn_ECC_CFG & 0x0f000002) | (1 << 0)) + & ~(1 << 1); + /* As per HPG the reset sequence as follow + * NAND_DEV0_CFG0 0x005400D0 or 0x00540010 + * NAND_DEVn_CFG1 0x087476B1 + * NAND_DEV0_ECC_CFG 0x02000001 + * NAND_FLASH_CMD 0x3800000D + * NAND_EXEC_CMD 0x00000001 + */ + /* write the reset sequence as per HPG */ + bam_add_cmd_element(cmd_list_ptr, NAND_DEV0_CFG0, (uint32_t)cfg0, + CE_WRITE_TYPE); + cmd_list_ptr++; + + bam_add_cmd_element(cmd_list_ptr, NAND_DEV0_CFG1, (uint32_t)cfg1, + CE_WRITE_TYPE); + cmd_list_ptr++; + + bam_add_cmd_element(cmd_list_ptr, NAND_DEV0_ECC_CFG, (uint32_t)ecc_cfg, + CE_WRITE_TYPE); + cmd_list_ptr++; + +#endif /* Issue the Reset device command to the NANDc */ bam_add_cmd_element(cmd_list_ptr, NAND_FLASH_CMD, (uint32_t)flash_cmd, CE_WRITE_TYPE); @@ -1002,9 +1579,13 @@ qpic_nand_add_isbad_cmd_ce(struct cfg_params *cfg, bam_add_cmd_element(cmd_list_ptr, NAND_DEV0_ECC_CFG, (uint32_t)cfg->ecc_cfg, CE_WRITE_TYPE); cmd_list_ptr++; - +#ifdef CONFIG_QPIC_SERIAL + bam_add_cmd_element(cmd_list_ptr, NAND_READ_LOCATION_LAST_CW_n(0), + (uint32_t)cfg->addr_loc_0, CE_WRITE_TYPE); +#else bam_add_cmd_element(cmd_list_ptr, NAND_READ_LOCATION_n(0), (uint32_t)cfg->addr_loc_0, CE_WRITE_TYPE); +#endif cmd_list_ptr++; cmd_list_ptr = qpic_nand_add_cmd_ce(cfg, cmd_list_ptr); @@ -1092,8 +1673,18 @@ static int qpic_nand_block_isbad(struct mtd_info *mtd, loff_t offs) /* Read the first page in the block. */ cwperpage = (dev->cws_per_page); - /* Read page cmd */ params.cmd = NAND_CMD_PAGE_READ_ECC; + + /* Read page cmd */ +#ifdef CONFIG_QPIC_SERIAL + params.cmd = NAND_CMD_PAGE_READ; + if (dev->quad_mode) + params.cmd |= QPIC_SPI_TRANSFER_MODE_X4; + else + params.cmd |= QPIC_SPI_TRANSFER_MODE_X1; + + params.cmd |= (QPIC_SPI_WP_SET | QPIC_SPI_HOLD_SET); +#endif /* Clear the CW per page bits */ params.cfg0 = dev->cfg0_raw & ~(7U << NAND_DEV0_CFG0_CW_PER_PAGE_SHIFT); @@ -1148,16 +1739,38 @@ qpic_nand_add_wr_page_cws_cmd_desc(struct mtd_info *mtd, struct cfg_params *cfg, int num_desc = 0; int int_flag = 0; unsigned int i; - - if (cfg_mode == NAND_CFG) - ecc = dev->ecc_bch_cfg; +#ifdef CONFIG_QPIC_SERIAL + /* For Serial NAND devices the page program sequence as + * 02H (PROGRAM LOAD)/32H (PROGRAM LOAD x4) + * 06H (WRITE ENABLE) + * 10H (PROGRAM EXECUTE) + * 0FH (GET FEATURE command to read the status) + * No need to 0x02 & 0x32 command manually, controller + * automatically send this command to device. we have already mapped + * these command in QPIC_FLASH_DEV_CMD9 register, similar for command + * 0x06 & 0x0F, controller will take care internally + * + * NOTE: While initializing we have already enabeld quad bit i.e QE-bit + * and disable write protection so no need to check here. + */ + if (dev->quad_mode) + cfg->cmd |= QPIC_SPI_TRANSFER_MODE_X4; else - ecc = 0x1; /* Disable ECC */ + cfg->cmd |= QPIC_SPI_TRANSFER_MODE_X1; + cfg->cmd |= (QPIC_SPI_WP_SET | QPIC_SPI_HOLD_SET); +#endif + + if (cfg_mode == NAND_CFG) { + ecc = dev->ecc_bch_cfg; + } else { + ecc = 0x1; /* Disable ECC */ + } /* Add ECC configuration */ bam_add_cmd_element(cmd_list_ptr, NAND_DEV0_ECC_CFG, (uint32_t)ecc, CE_WRITE_TYPE); cmd_list_ptr++; + cmd_list_ptr = qpic_nand_add_addr_n_cfg_ce(cfg, cmd_list_ptr); bam_add_cmd_element(cmd_list_ptr, NAND_FLASH_CMD, @@ -1775,13 +2388,26 @@ qpic_nand_read_page(struct mtd_info *mtd, uint32_t page, unsigned char *buffer_st, *spareaddr_st; unsigned int max_bitflips = 0, uncorrectable_err_cws = 0; + /* Check This address for serial NAND later on if any issue + * Because as per HPG Page Read 0x13 NAND_ADDR1[7:0] + * NAND_ADDR0[31:24] NAND_ADDR0[23:16] + */ params.addr0 = page << 16; params.addr1 = (page >> 16) & 0xff; + if (cfg_mode == NAND_CFG_RAW) { params.cfg0 = dev->cfg0_raw; params.cfg1 = dev->cfg1_raw; params.cmd = NAND_CMD_PAGE_READ; ecc = 0x1; /* Disable ECC */ +#ifdef CONFIG_QPIC_SERIAL + if (dev->quad_mode) + params.cmd |= QPIC_SPI_TRANSFER_MODE_X4; + else + params.cmd |= QPIC_SPI_TRANSFER_MODE_X1; + + params.cmd |= (QPIC_SPI_WP_SET | QPIC_SPI_HOLD_SET); +#endif data_bytes = dev->cw_size; oob_bytes = mtd->oobsize; ud_bytes_in_last_cw = (dev->cw_size - mtd->oobsize); @@ -1789,14 +2415,22 @@ qpic_nand_read_page(struct mtd_info *mtd, uint32_t page, params.cfg0 = dev->cfg0; params.cfg1 = dev->cfg1; params.cmd = NAND_CMD_PAGE_READ_ALL; +#ifdef CONFIG_QPIC_SERIAL + if (dev->quad_mode) + params.cmd |= QPIC_SPI_TRANSFER_MODE_X4; + else + params.cmd |= QPIC_SPI_TRANSFER_MODE_X1; + + params.cmd |= (QPIC_SPI_WP_SET | QPIC_SPI_HOLD_SET); +#endif ecc = (dev->ecc_bch_cfg); data_bytes = DATA_BYTES_IN_IMG_PER_CW; ud_bytes_in_last_cw = USER_DATA_BYTES_PER_CW - (((dev->cws_per_page) - 1) << 2); oob_bytes = DATA_BYTES_IN_IMG_PER_CW - ud_bytes_in_last_cw; } - params.exec = 1; + params.exec = 1; /* Read all the Data bytes in the first 3 CWs. */ addr_loc_0 = NAND_RD_LOC_OFFSET(0); addr_loc_0 |= NAND_RD_LOC_SIZE(data_bytes);; @@ -1844,12 +2478,19 @@ qpic_nand_read_page(struct mtd_info *mtd, uint32_t page, cmd_list_ptr++; if (i == (dev->cws_per_page) - 1) { + /* Write addr loc 1 only for the last CW. */ addr_loc_0 = NAND_RD_LOC_OFFSET(0); addr_loc_0 |= NAND_RD_LOC_SIZE(ud_bytes_in_last_cw); addr_loc_0 |= NAND_RD_LOC_LAST_BIT(0); - /* Write addr loc 1 only for the last CW. */ +#ifdef CONFIG_QPIC_SERIAL + /*To read only spare bytes 80 0r 16*/ + bam_add_cmd_element(cmd_list_ptr, NAND_READ_LOCATION_LAST_CW_n(1), + (uint32_t)addr_loc_1, CE_WRITE_TYPE); +#else bam_add_cmd_element(cmd_list_ptr, NAND_READ_LOCATION_n(1), (uint32_t)addr_loc_1, CE_WRITE_TYPE); +#endif + cmd_list_ptr++; flags = 0; /* Add Data desc */ @@ -1877,12 +2518,23 @@ qpic_nand_read_page(struct mtd_info *mtd, uint32_t page, bam_sys_gen_event(&bam, DATA_PRODUCER_PIPE_INDEX, num_data_desc); } - /* Write addr loc 0. */ - bam_add_cmd_element(cmd_list_ptr, +#ifdef CONFIG_QPIC_SERIAL + if (i == (dev->cws_per_page) - 1) + bam_add_cmd_element(cmd_list_ptr, + NAND_READ_LOCATION_LAST_CW_n(0), + (uint32_t)addr_loc_0, + CE_WRITE_TYPE); + else + bam_add_cmd_element(cmd_list_ptr, NAND_READ_LOCATION_n(0), (uint32_t)addr_loc_0, CE_WRITE_TYPE); - +#else + bam_add_cmd_element(cmd_list_ptr, + NAND_READ_LOCATION_n(0), + (uint32_t)addr_loc_0, + CE_WRITE_TYPE); +#endif cmd_list_ptr++; bam_add_cmd_element(cmd_list_ptr, @@ -2064,6 +2716,7 @@ static int qpic_nand_read_oob(struct mtd_info *mtd, loff_t to, ret = qpic_nand_read_page(mtd, start_page + i, cfg_mode, &page_ops); + if (ret < 0) { printf("%s: reading page %d failed with %d err\n", __func__, start_page + i, ret); @@ -2314,7 +2967,28 @@ nand_result_t qpic_nand_blk_erase(struct mtd_info *mtd, uint32_t page) /* Clear CW_PER_PAGE in cfg0 */ cfg.cfg0 = dev->cfg0 & ~(7U << NAND_DEV0_CFG0_CW_PER_PAGE_SHIFT); cfg.cfg1 = dev->cfg1; + cfg.cmd = NAND_CMD_BLOCK_ERASE; +#ifdef CONFIG_QPIC_SERIAL + /* For serial NAND devices the block erase sequence is + * Issue 06H (WRITE ENBALE command) + * Issue D8H (BLOCK ERASE command) + * Issue 0FH (GET FEATURES command to read the status register) + * But we have already mapped write enable command in register + * QPIC_FLASH_DEV_CMD7 so here no need to send this command manually + * once we will send block erase command then controller internally + * send write enable command + * similar for Get feature command, no neeed to send this command + * also manually controller will take care. + * + * NOTE: Initially we are disabling block protection, so no need + * to do it again here. + */ + cfg.addr0 = page << 16; + cfg.cmd = 0xA; + cfg.cmd |= (QPIC_SPI_WP_SET | QPIC_SPI_HOLD_SET | + QPIC_SPI_TRANSFER_MODE_X1); +#endif cfg.exec = 1; cmd_list_ptr = qpic_nand_add_cmd_ce(&cfg, cmd_list_ptr); @@ -2418,13 +3092,13 @@ qpic_nand_erase(struct mtd_info *mtd, struct erase_info *instr) for (i = start; i < (start + blocks); i++) { offs = i << chip->phys_erase_shift; pageno = offs >> chip->page_shift; + /* Erase only if the block is not bad */ if (!instr->scrub && qpic_nand_block_isbad(mtd, offs)) { printf("NAND Erase error: Block address belongs to " "bad block: %ld\n", (pageno / (dev->num_pages_per_blk))); return -EIO; } - ret = qpic_nand_blk_erase(mtd, pageno); if (ret) { instr->fail_addr = offs; @@ -2519,6 +3193,25 @@ void qpic_nand_init(void) return; } +#ifdef CONFIG_QPIC_SERIAL + /* Read the Hardware Version register */ + hw_ver = readl(NAND_VERSION); + /* Only maintain major number */ + hw_ver >>= 28; + if (hw_ver >= QCA_QPIC_V2_1_1) { + printf("QPIC controller support serial NAND\n"); + } else { + printf("%s : Qpic controller not support serial NAND\n", + __func__); + return; + } + + qpic_spi_init(mtd); +#ifdef MULTI_PAGE_READ + config.pipes.status_pipe = NAND_BAM_STATUS_PIPE; + config.pipes.status_pipe_grp = NAND_BAM_STATUS_PIPE_GRP; +#endif +#endif config.pipes.read_pipe = DATA_PRODUCER_PIPE; config.pipes.write_pipe = DATA_CONSUMER_PIPE; config.pipes.cmd_pipe = CMD_PIPE; @@ -2544,13 +3237,27 @@ void qpic_nand_init(void) else if (ret > 0) qpic_nand_non_onfi_probe(mtd); +#ifndef CONFIG_QPIC_SERIAL qpic_config_timing_parameters(mtd); - +#endif /* Save the RAW and read/write configs */ ret = qpic_nand_save_config(mtd); if (ret < 0) return; +#ifdef CONFIG_QPIC_SERIAL + /* Check all blocks of serial NAND device is unlocked or + * not if not then unlock the all the blocks of serial NAND + * device also check the internal ecc is enabled or not if internal + * ecc is enabled then disable internal ecc using get/set feature + * command. + */ + ret = qpic_spi_nand_config(mtd); + if (ret < 0) { + printf("%s : Issue with Serial Nand configuration.\n",__func__); + return; + } +#endif dev = MTD_QPIC_NAND_DEV(mtd); qpic_nand_mtd_params(mtd); diff --git a/include/configs/ipq5018.h b/include/configs/ipq5018.h index e9a893ebe4..dfcfe53cba 100644 --- a/include/configs/ipq5018.h +++ b/include/configs/ipq5018.h @@ -130,6 +130,10 @@ extern loff_t board_env_size; #define CONFIG_SYS_NAND_SELF_INIT #define CONFIG_SYS_NAND_ONFI_DETECTION +/* QSPI Flash configs + */ +#define CONFIG_QPIC_SERIAL + /* * SPI Flash Configs */