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 */