// Parse SFDP parameters and then fill into FlexSPI Serial NOR Configuration Block status_t parse_sfdp(uint32_t instance, flexspi_nor_config_t *config, jedec_info_table_t *tbl, serial_nor_config_option_t *option) { status_t status = kStatus_InvalidArgument; debug_printf("\n\r DP: Entering parse_sfdp() \n\r");//*** do { debug_printf("\n\r DP:parse_sfdp() : do Entering \n\r");//*** jedec_flash_param_table_t *param_tbl = &tbl->flash_param_tbl; jedec_4byte_addressing_inst_table_t *flash_4b_tbl = &tbl->flash_4b_inst_tbl; // Check whether DDR mode is supported. bool support_ddr_mode = false; if (option->option0.B.device_type == kSerialNorCfgOption_DeviceType_ReadSFDP_DDR) { support_ddr_mode = param_tbl->misc.support_ddr_clocking; debug_printf("\n\r DP:parse_sfdp() : DDR mode support validation %d; %d = \n\r", option->option0.B.device_type, support_ddr_mode); if (!support_ddr_mode) { debug_printf("\n\r DP:parse_sfdp() : break support_ddr_mode = %d \n\r", support_ddr_mode); break; } } config->memConfig.readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackInternally; config->memConfig.serialClkFreq = option->option0.B.max_freq; uint8_t read_cmd; uint32_t dummy_cycles = 0; uint8_t mode_cycles = 0; uint32_t sector_erase_cmd; uint32_t block_erase_cmd; uint32_t address_bits = 24; uint32_t address_pads = FLEXSPI_1PAD; debug_printf("\n\r DP:parse_sfdp() : mode_cycles=%d; dummy_cycles=%d \n\r", mode_cycles, dummy_cycles);//*** debug_printf("\n\r DP:parse_sfdp() : call get_page_sector_block_size_from_sfdp() \n\r");//*** get_page_sector_block_size_from_sfdp(config, tbl, §or_erase_cmd, &block_erase_cmd); if (config->memConfig.sflashA1Size > MAX_24BIT_ADDRESSING_SIZE)//1,67,77,216 { debug_printf("\n\r DP:parse_sfdp() : config->memConfig.sflashA1Size > MAX_24BIT_ADDRESSING_SIZE \n\r"); address_bits = 32; } uint32_t cmd_pads = option->option0.B.cmd_pads; if (cmd_pads == FLEXSPI_1PAD) { debug_printf("\n\r DP:parse_sfdp() : cmd_pads == FLEXSPI_1PAD \n\r");//*** // Prepare Quad Mode enable sequence as needed. status = prepare_quad_mode_enable_sequence(instance, config, tbl, option);//*** if (status != kStatus_Success) { debug_printf("\n\r DP:parse_sfdp() : prepare_quad_mode_enable_sequence fails \n\r"); break; } // Determine Read command based on SFDP if (param_tbl->misc.supports_1_4_4_fast_read) { address_pads = FLEXSPI_4PAD; mode_cycles = param_tbl->read_1_4_info.mode_clocks_1_4_4_read; dummy_cycles = param_tbl->read_1_4_info.dummy_clocks_1_4_4_read; debug_printf("\n\r DP:parse_sfdp() :misc.supports_1_4_4_fast_read-> mode_cycles=%d; dummy_cycles=%d \n\r", mode_cycles, dummy_cycles);//*** X1:2,10; E1:2,4 } else if (param_tbl->misc.support_1_1_4_fast_read) { mode_cycles = param_tbl->read_1_4_info.mode_clocks_1_1_4_read; dummy_cycles = param_tbl->read_1_4_info.dummy_clocks_1_1_4_read; debug_printf("\n\r DP:parse_sfdp() :misc.support_1_1_4_fast_read-> mode_cycles=%d; dummy_cycles=%d \n\r", mode_cycles, dummy_cycles); } // Page Program if (address_bits == 32) { debug_printf("\n\r DP:parse_sfdp() : address_bits == 32 \n\r"); if (tbl->has_4b_addressing_inst_table) { if (flash_4b_tbl->cmd_4byte_support_info.support_1_4_4_page_program) { debug_printf("\n\r DP:parse_sfdp() : 1_4_4_page_program \n\r"); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM] = FLEXSPI_LUT_SEQ( CMD_SDR, FLEXSPI_1PAD, kSerialNorCmd_PageProgram_1_4_4_4B, RADDR_SDR, FLEXSPI_4PAD, 32); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0); } else if (flash_4b_tbl->cmd_4byte_support_info.support_1_1_4_page_program) { debug_printf("\n\r DP:parse_sfdp() : 1_1_4_page_program \n\r"); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM] = FLEXSPI_LUT_SEQ( CMD_SDR, FLEXSPI_1PAD, kSerialNorCmd_PageProgram_1_1_4_4B, RADDR_SDR, FLEXSPI_1PAD, 32); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_4PAD, 0x04, STOP, FLEXSPI_1PAD, 0); } else // 1_1_1_page_program { debug_printf("\n\r DP:parse_sfdp() : 1_1_1_page_program \n\r"); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM] = FLEXSPI_LUT_SEQ( CMD_SDR, FLEXSPI_1PAD, kSerialNorCmd_PageProgram_1_1_1_4B, RADDR_SDR, FLEXSPI_1PAD, 32); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0); } } else { debug_printf("\n\r DP:parse_sfdp() : tbl->has_4b_addressing_inst_table!=1 \n\r"); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM] = FLEXSPI_LUT_SEQ( CMD_SDR, FLEXSPI_1PAD, kSerialNorCmd_PageProgram_1_1_1_4B, RADDR_SDR, FLEXSPI_1PAD, 32); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0); } } else // Only consider 1-1-1 Program { debug_printf("\n\r DP:parse_sfdp() : Only consider 1_1_1_page_program and address_bits!=32 \n\r");//*** config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM] = FLEXSPI_LUT_SEQ( CMD_SDR, FLEXSPI_1PAD, kSerialNorCmd_PageProgram_1_1_1_3B, RADDR_SDR, FLEXSPI_1PAD, 24); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM + 1] = FLEXSPI_LUT_SEQ(WRITE_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0); } } else { debug_printf("\n\r DP:parse_sfdp() : cmd_pads != FLEXSPI_1PAD \n\r"); break; } config->memConfig.readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackFromDqsPad; // Write Enable config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, kSerialNorCmd_WriteEnable, STOP, FLEXSPI_1PAD, 0); // ReadStatus config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, kSerialNorCmd_ReadStatusReg1, READ_SDR, FLEXSPI_1PAD, 0x04); // Erase Sector config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, sector_erase_cmd, RADDR_SDR, FLEXSPI_1PAD, address_bits); // Erase Block config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, block_erase_cmd, RADDR_SDR, FLEXSPI_1PAD, address_bits); // Erase All config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_CHIPERASE] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, kSerialNorCmd_ChipErase, STOP, FLEXSPI_1PAD, 0); // Calculate dummy cycles if (option->option0.B.option_size && option->option1.B.dummy_cycles != 0) { mode_cycles = 0; dummy_cycles = option->option1.B.dummy_cycles; debug_printf("\n\r DP:parse_sfdp() : dummy_cycles=%d \n\r", dummy_cycles); if (support_ddr_mode) { dummy_cycles *= 2; debug_printf("\n\r DP:parse_sfdp() : if (support_ddr_mode)->dummy_cycles=%d \n\r", dummy_cycles); } } // Try to do ddr dummy probe for ddr read when the dummy cycle is not provided else if (support_ddr_mode) { if (address_bits == 32) { debug_printf("\n\r DP:parse_sfdp() : else if (support_ddr_mode) \n\r"); // Basic read command config->memConfig.lookupTable[0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x13, RADDR_SDR, FLEXSPI_1PAD, 32); config->memConfig.lookupTable[1] = FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 1); } status = flexspi_nor_flash_init(instance, config); if (status != kStatus_Success) { debug_printf("\n\r DP:parse_sfdp() : flexspi_nor_flash_init fails \n\r"); break; } // Probe dummy_cycles status = probe_dtr_quad_read_dummy_cycles(instance, config, &dummy_cycles); if (status != kStatus_Success) { debug_printf("\n\r DP:parse_sfdp() : probe_dtr_quad_read_dummy_cycles \n\r"); // Cannot probe dummy cycle for DDR read break; } debug_printf("\n\r DP:parse_sfdp() :mode_cycles=%d; dummy_cycles=%d \n\r", mode_cycles, dummy_cycles); mode_cycles = 0; } // Generate Flash Read sequence if (address_bits == 24) { debug_printf("\n\r DP:parse_sfdp() : address_bits == 24 \n\r");//*** if (support_ddr_mode) { debug_printf("\n\r DP:parse_sfdp() : address_bits == 24 -> support_ddr_mode \n\r"); read_cmd = kSerialNorCmd_Read_DDR_1_4_4_3B; } else if (param_tbl->misc.supports_1_4_4_fast_read) { debug_printf("\n\r DP:parse_sfdp() : address_bits == 24 -> param_tbl->misc.supports_1_4_4_fast_read \n\r");//*** read_cmd = param_tbl->read_1_4_info.inst_1_4_4_read; } else if (param_tbl->misc.support_1_1_4_fast_read) { debug_printf("\n\r DP:parse_sfdp() : address_bits == 24 -> param_tbl->misc.support_1_1_4_fast_read \n\r"); read_cmd = param_tbl->read_1_4_info.inst_1_1_4_read; } else // Use basic read if the Quad Read is not supported { debug_printf("\n\r DP:parse_sfdp() : address_bits == 24 -> else \n\r"); read_cmd = kSerialNorCmd_BasicRead_3B; dummy_cycles = 0; mode_cycles = 0; } } else // 32bit addressing mode { debug_printf("\n\r DP:parse_sfdp() : else address_bits == 32 \n\r"); if (support_ddr_mode) { debug_printf("\n\r DP:parse_sfdp() : else address_bits == 32 -> support_ddr_mode \n\r"); read_cmd = kSerialNorCmd_Read_DDR_1_4_4_4B; address_pads = FLEXSPI_4PAD; } else if (tbl->has_4b_addressing_inst_table) { if (flash_4b_tbl->cmd_4byte_support_info.support_1_4_4_fast_read) { debug_printf("\n\r DP:parse_sfdp() : flash_4b_tbl->cmd_4byte_support_info.support_1_4_4_fast_read \n\r"); read_cmd = kSerialNorCmd_Read_SDR_1_4_4_4B; address_pads = FLEXSPI_4PAD; } else if (flash_4b_tbl->cmd_4byte_support_info.support_1_1_4_fast_read) { debug_printf("\n\r DP:parse_sfdp() : flash_4b_tbl->cmd_4byte_support_info.support_1_1_4_fast_read \n\r"); read_cmd = kSerialNorCmd_Read_SDR_1_1_4_4B; address_pads = FLEXSPI_1PAD; } else { debug_printf("\n\r DP:parse_sfdp() : else tbl->has_4b_addressing_inst_table\n\r"); read_cmd = kSerialNorCmd_BasicRead_4B; dummy_cycles = 0; mode_cycles = 0; } } // For device that is only compliant with JESD216 else if (param_tbl->misc.supports_1_4_4_fast_read) { debug_printf("\n\r DP:parse_sfdp() : else if - param_tbl->misc.supports_1_4_4_fast_read \n\r"); read_cmd = kSerialNorCmd_Read_SDR_1_4_4_4B; } else if (param_tbl->misc.support_1_1_4_fast_read) { debug_printf("\n\r DP:parse_sfdp() : else if - param_tbl->misc.support_1_1_4_fast_read \n\r"); read_cmd = kSerialNorCmd_Read_SDR_1_1_4_4B; } else { debug_printf("\n\r DP:parse_sfdp() : else ..\n\r"); read_cmd = kSerialNorCmd_BasicRead_4B; dummy_cycles = 0; mode_cycles = 0; } } // Read LUT if (support_ddr_mode) { debug_printf("\n\r DP:parse_sfdp() : Read LUT support_ddr_mode \n\r"); config->memConfig.controllerMiscOption |= FLEXSPI_BITMASK(kFlexSpiMiscOffset_DdrModeEnable); config->memConfig.lookupTable[0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, read_cmd, RADDR_DDR, FLEXSPI_4PAD, address_bits); } else { debug_printf("\n\r DP:parse_sfdp() : else Read LUT support_ddr_mode \n\r");//*** config->memConfig.lookupTable[0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, read_cmd, RADDR_SDR, address_pads, address_bits); } uint32_t enhance_mode = 0x00; if (option->option0.B.misc_mode == kSerialNorEnhanceMode_Disabled) { // Treat mode cycles as dummy cycles dummy_cycles += mode_cycles; mode_cycles = 0; debug_printf("\n\r DP:parse_sfdp() :option->option0.B.misc_mode == kSerialNorEnhanceMode_Disabled->mode_cycles=%d; dummy_cycles=%d \n\r", mode_cycles, dummy_cycles);//*** X1:0,12; E1:0,6 } #if FLEXSPI_ENABLE_NO_CMD_MODE_SUPPORT else if (option->option0.B.misc_mode == kSerialNorEnhanceMode_0_4_4_Mode) { // Cannot detect the 0-4-4 mode entry method, disable 0-4-4 mode if ((tbl->flash_param_tbl_size < kSfdp_BasicProtocolTableSize_RevA) || (!param_tbl->mode_4_4_info.support_mode_0_4_4)) { dummy_cycles += mode_cycles; mode_cycles = 0; debug_printf("\n\r DP:parse_sfdp() : kSerialNorEnhanceMode_0_4_4_Mode->mode_cycles=%d; dummy_cycles=%d \n\r", mode_cycles, dummy_cycles); } else { uint32_t entry_method = param_tbl->mode_4_4_info.mode_0_4_4_entry_method; if ((entry_method & 0x01) || (entry_method & 0x04)) { enhance_mode = 0xA5; } else if (entry_method & 0x02) { status = prepare_0_4_4_mode_enable_sequence(instance, config, tbl, option); if (status != kStatus_Success) { break; } enhance_mode = 0x01; } // Refer to JESD216B 6.4.18 for more details. uint32_t exit_method = param_tbl->mode_4_4_info.mode_0_4_4_exit_method; if ((exit_method & 0x02) || (exit_method & 0x08)) { // Send 8-10 cycles of 0xF depends on addressing mode config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xFF, CMD_SDR, FLEXSPI_4PAD, 0xFF); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD + 1] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xFF, CMD_SDR, FLEXSPI_4PAD, 0xFF); if (address_bits == 32) { config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD + 2] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0xFF, STOP, FLEXSPI_1PAD, 0); } } else if ((exit_method & 0x01) || (exit_method & 0x10)) { // Use command to simulate read access to 0 using mode 0x00 config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0x00, CMD_SDR, FLEXSPI_4PAD, 0x00); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD + 1] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_4PAD, 0x00, CMD_SDR, FLEXSPI_4PAD, 0x00); config->memConfig.lookupTable[4 * NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD + 2] = FLEXSPI_LUT_SEQ(MODE8_SDR, FLEXSPI_4PAD, 0x00, DUMMY_SDR, FLEXSPI_4PAD, 0x10); } else { break; } config->needExitNoCmdMode = true; } } #endif // FLEXSPI_ENABLE_NO_CMD_MODE_SUPPORT else { debug_printf("\n\r DP:parse_sfdp() : FLEXSPI_ENABLE_NO_CMD_MODE_SUPPORT \n\r"); break; } debug_printf("\n\r DP:parse_sfdp() : mode_cycles=%d; dummy_cycles=%d \n\r", mode_cycles, dummy_cycles);//*** X1:0,12; E1:0,6 /*Added by econ_CST*/ /*Old SPI IC - MX25R4035FM1IL0 New SPI IC - AT25XE041D-SSHN-T mode_cycles = 0 for both IC dummy_cycles = 12 for New SPI IC and 6 for Old SPI IC But according to the datasheet of New SPI IC we need only 2 dummycycles for read operation after command. Hence As of now we hardcoded the dummy_cycles value to 2. Will Find the rootcause and fix this issue in upcoming release.*/ if(dummy_cycles == 12) { dummy_cycles = 2; } debug_printf("\n\r DP:parse_sfdp() : mode_cycles=%d; dummy_cycles=%d \n\r", mode_cycles, dummy_cycles); if (mode_cycles == 0) { if (dummy_cycles > 0) { if (support_ddr_mode) { config->memConfig.lookupTable[1] = FLEXSPI_LUT_SEQ(DUMMY_DDR, FLEXSPI_4PAD, dummy_cycles, READ_DDR, FLEXSPI_4PAD, 0x04); } else { config->memConfig.lookupTable[1] = FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, dummy_cycles, READ_SDR, FLEXSPI_4PAD, 0x04); } } else // Only applicable to basic read command, all other read commands require dummy cycles { config->memConfig.lookupTable[1] = FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_1PAD, 0x04, STOP, FLEXSPI_1PAD, 0x0); } } else { uint32_t mode_inst; #if 0 // Comment out this segment because in JESD216A/B, below logic cannot happen, keep the codes here in case it can // be used for later JESD216 revision if (support_ddr_mode) { if (mode_cycles == 1) { mode_inst = MODE4_DDR; enhance_mode >>= 4; } else { mode_inst = MODE8_DDR; } config->memConfig.lookupTable[1] = FLEXSPI_LUT_SEQ(mode_inst, FLEXSPI_4PAD, enhance_mode, DUMMY_DDR, FLEXSPI_4PAD, dummy_cycles); config->memConfig.lookupTable[2] = FLEXSPI_LUT_SEQ(READ_DDR, FLEXSPI_4PAD, 0x04, JMP_ON_CS, FLEXSPI_1PAD, 1); } else #endif { if (mode_cycles == 1) { mode_inst = MODE4_SDR; enhance_mode >>= 4; } else { mode_inst = MODE8_SDR; } config->memConfig.lookupTable[1] = FLEXSPI_LUT_SEQ(mode_inst, FLEXSPI_4PAD, enhance_mode, DUMMY_SDR, FLEXSPI_4PAD, dummy_cycles); config->memConfig.lookupTable[2] = FLEXSPI_LUT_SEQ(READ_SDR, FLEXSPI_4PAD, 0x04, JMP_ON_CS, FLEXSPI_1PAD, 1); } } // For QuadSPI Flash, only the Read command is DDR instruction, other commands are all DDR instructions, // In FlexSPI design, the clock for DDR mode must be configured as 2 * real clock, so when the system is // configured to // DDR mode, if the non-read commands are executed, the clock is 2 * real clock, this may cause the clock for // SDR command // to exceed the spec, so, here we introduce the halfClkForNonReadCmd field, once this field is set, FlexSPI // Driver // will half the clock for all non-read instruction to ensure the clock for these commands meets SPEC. if (support_ddr_mode) { debug_printf("\n\r DP:parse_sfdp() : last support_ddr_mode \n\r"); config->halfClkForNonReadCmd = true; config->memConfig.controllerMiscOption |= FLEXSPI_BITMASK(kFlexSpiMiscOffset_DdrModeEnable); } // Always enable Safe configuration Frequency config->memConfig.controllerMiscOption |= FLEXSPI_BITMASK(kFlexSpiMiscOffset_SafeConfigFreqEnable); status = kStatus_Success; } while (0); debug_printf("\n\r DP: Leaving parse_sfdp() \n\r");//*** return status; }