/**************************************************************************/ /* */ /* Copyright (c) Microsoft Corporation. All rights reserved. */ /* */ /* This software is licensed under the Microsoft Software License */ /* Terms for Microsoft Azure RTOS. Full text of the license can be */ /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ /* and in the root directory of this software. */ /* */ /**************************************************************************/ #include "lx_stm32_nand_custom_driver.h" static UINT lx_nand_driver_read(ULONG block, ULONG page, ULONG *destination, ULONG words); static UINT lx_nand_driver_write(ULONG block, ULONG page, ULONG *source, ULONG words); static UINT lx_nand_driver_block_erase(ULONG block, ULONG erase_count); static UINT lx_nand_driver_block_erased_verify(ULONG block); static UINT lx_nand_driver_page_erased_verify(ULONG block, ULONG page); static UINT lx_nand_driver_block_status_get(ULONG block, UCHAR *bad_block_byte); static UINT lx_nand_driver_block_status_set(ULONG block, UCHAR bad_block_byte); //static UINT lx_nand_driver_extra_bytes_get(ULONG block, ULONG page, UCHAR *destination, UINT size); //static UINT lx_nand_driver_extra_bytes_set(ULONG block, ULONG page, UCHAR *source, UINT size); static UINT lx_nand_driver_system_error(UINT error_code, ULONG block, ULONG page); /* USER CODE BEGIN 0 */ #include "WB_SerialNAND_Sample_Code_LLD.h" // Include this line #include "stdio.h" static UINT _lx_nand_flash_erase_all_driver(VOID); static UCHAR flash_is_initialized = 0; static ULONG nand_flash_rw_buffer[WORDS_PER_PHYSICAL_PAGE] = {0}; //static UCHAR Buffer_Spare_Area[SPARE_BYTES_PER_PAGE] = {0}; /* USER CODE END 0 */ #ifndef WORDS_PER_PHYSICAL_PAGE #define WORDS_PER_PHYSICAL_PAGE 512 #endif ULONG nand_flash_buffer[WORDS_PER_PHYSICAL_PAGE]; UINT lx_stm32_nand_custom_driver_initialize(LX_NAND_FLASH *nand_flash) { UINT ret = LX_SUCCESS; ULONG total_blocks = 0; ULONG pages_per_block = 0; ULONG bytes_per_page = 0; /* USER CODE BEGIN Init_Section_0 */ total_blocks = TOTAL_BLOCKS; pages_per_block = PHYSICAL_PAGES_PER_BLOCK; bytes_per_page = BYTES_PER_PHYSICAL_PAGE; /*USER CODE END Init_Section_0 */ nand_flash->lx_nand_flash_total_blocks = total_blocks; nand_flash->lx_nand_flash_pages_per_block = pages_per_block; nand_flash->lx_nand_flash_bytes_per_page = bytes_per_page; /* USER CODE BEGIN Init_Section_1 */ if (!flash_is_initialized) { if(W25NXX_Init() == 1) { printf("successfully initialized\n"); } /* If ERASE_CHIP enabled erase the NAND device */ #ifdef LX_DRIVER_ERASES_FLASH_AFTER_INIT if (_lx_nand_flash_erase_all_driver() != LX_SUCCESS) { return (LX_ERROR); } #endif flash_is_initialized = 1; } /*USER CODE END Init_Section_1 */ nand_flash->lx_nand_flash_driver_read = lx_nand_driver_read; nand_flash->lx_nand_flash_driver_write = lx_nand_driver_write; nand_flash->lx_nand_flash_driver_block_erase = lx_nand_driver_block_erase; nand_flash->lx_nand_flash_driver_block_erased_verify = lx_nand_driver_block_erased_verify; nand_flash->lx_nand_flash_driver_page_erased_verify = lx_nand_driver_page_erased_verify; nand_flash->lx_nand_flash_driver_block_status_get = lx_nand_driver_block_status_get; nand_flash->lx_nand_flash_driver_block_status_set = lx_nand_driver_block_status_set; nand_flash->lx_nand_flash_driver_extra_bytes_get = lx_nand_driver_extra_bytes_get; nand_flash->lx_nand_flash_driver_extra_bytes_set = lx_nand_driver_extra_bytes_set; nand_flash->lx_nand_flash_driver_system_error = lx_nand_driver_system_error; /* USER CODE BEGIN Init_Section_2 */ /*USER CODE END Init_Section_2 */ nand_flash->lx_nand_flash_page_buffer = &nand_flash_buffer[0]; /* USER CODE BEGIN Init_Section_3 */ /*USER CODE END Init_Section_3 */ return ret; } static UINT lx_nand_driver_read(ULONG block, ULONG page, ULONG *destination, ULONG words) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN driver_read */ INT status = 0; ULONG byte_address = ((block * PHYSICAL_PAGES_PER_BLOCK) + page) * BYTES_PER_PHYSICAL_PAGE; printf("LX Read: Block: %lu, Page: %lu\n", block, page); //printf("QSPI Read Page: %d\n", page); status = W25NXX_Read_Page((UCHAR *) destination, byte_address, BYTES_PER_PHYSICAL_PAGE); if (status != BYTES_PER_PHYSICAL_PAGE) { return LX_ERROR; // Failure } else { return LX_SUCCESS; } /* USER CODE END driver_read */ return ret; } static UINT lx_nand_driver_write(ULONG block, ULONG page, ULONG *source, ULONG words) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN driver_write */ INT status = 0; ULONG byte_address = ((block * PHYSICAL_PAGES_PER_BLOCK) + page) * BYTES_PER_PHYSICAL_PAGE; printf("LX Write: Block: %lu, Page: %lu\n", block, page); //printf("QSPI Write Page: %d\n", page); status = W25NXX_Write_Page((UCHAR *) source, byte_address, BYTES_PER_PHYSICAL_PAGE); if (status != BYTES_PER_PHYSICAL_PAGE) { return LX_ERROR; // Failure } else { return LX_SUCCESS; } /* USER CODE END driver_write */ return ret; } static UINT lx_nand_driver_block_erase(ULONG block, ULONG erase_count) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN block_erase */ if(W25NXX_Erase_Block128K(block) != 1) { ret = LX_ERROR; } /* USER CODE END block_erase */ return ret; } static UINT lx_nand_driver_block_erased_verify(ULONG block) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN block_erase_verify */ uint32_t index = 0, page = 0; for (index = 0; index < PHYSICAL_PAGES_PER_BLOCK ; index++) { if (lx_nand_driver_page_erased_verify(block, page) != LX_SUCCESS) { return (LX_ERROR); } page++; } /* USER CODE END block_erase_verify */ return ret; } static UINT lx_nand_driver_page_erased_verify(ULONG block, ULONG page) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN page_erased_verify */ ULONG *word_ptr; ULONG words; memset(nand_flash_rw_buffer, 0, sizeof(nand_flash_rw_buffer)); ULONG byte_address = ((block * PHYSICAL_PAGES_PER_BLOCK) + page) * BYTES_PER_PHYSICAL_PAGE; INT status = W25NXX_Read_Page((UCHAR *) nand_flash_rw_buffer, byte_address, BYTES_PER_PHYSICAL_PAGE); if (status != BYTES_PER_PHYSICAL_PAGE) { return LX_ERROR; // Failure } word_ptr = (ULONG *) & (nand_flash_rw_buffer[0]); /* Calculate the number of words in a page. */ words = WORDS_PER_PHYSICAL_PAGE; /* Loop to read flash. */ while (words--) { /* Is this word erased? */ if (*word_ptr++ != 0xFFFFFFFF) { return (LX_ERROR); } } /* USER CODE END page_erased_verify */ return ret; } static UINT lx_nand_driver_block_status_get(ULONG block, UCHAR *bad_block_byte) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN block_status_get */ *bad_block_byte = LX_NAND_GOOD_BLOCK; //(UCHAR) Buffer_Spare_Area[BAD_BLOCK_POSITION]; /* USER CODE END block_status_get*/ return ret; } static UINT lx_nand_driver_block_status_set(ULONG block, UCHAR bad_block_byte) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN block_status_set */ /* USER CODE END block_status_set */ return ret; } UINT lx_nand_driver_extra_bytes_get(ULONG block, ULONG page, UCHAR *destination, UINT size) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN extra_bytes_get */ ULONG byte_address = ((block * PHYSICAL_PAGES_PER_BLOCK) + page) * BYTES_PER_PHYSICAL_PAGE; if(W25NXX_Read_Spare_Area(byte_address, (UCHAR *) destination, size) != 0) { ret = LX_ERROR; } /* USER CODE END extra_bytes_get */ return ret; } UINT lx_nand_driver_extra_bytes_set(ULONG block, ULONG page, UCHAR *source, UINT size) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN extra_bytes_set */ ULONG byte_address = ((block * PHYSICAL_PAGES_PER_BLOCK) + page) * BYTES_PER_PHYSICAL_PAGE; if(W25NXX_Write_Spare_Area(byte_address, (UCHAR *) source, size) != 0) { ret = LX_ERROR; } /* USER CODE END extra_bytes_set */ return ret; } static UINT lx_nand_driver_system_error(UINT error_code, ULONG block, ULONG page) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN system_error */ // LX_PARAMETER_NOT_USED(error_code); // LX_PARAMETER_NOT_USED(block); // LX_PARAMETER_NOT_USED(page); printf("Lx Error- ErrCode: %d, BLK: %ld, PG: %ld\n", error_code, block, page); /* Custom processing goes here... all errors except for LX_NAND_ERROR_CORRECTED are fatal. */ ret = LX_ERROR; /* USER CODE END system_error */ return ret; } /* USER CODE BEGIN 1 */ static UINT lx_nand_flash_driver_pages_read(ULONG block, ULONG page, UCHAR *main_buffer, UCHAR *spare_buffer, ULONG pages) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN driver_pages_read */ ULONG i; for (i = 0; i < pages; i++) { if (main_buffer) { if (lx_nand_driver_read(block, page + i, (ULONG*)(main_buffer + i * BYTES_PER_PHYSICAL_PAGE), WORDS_PER_PHYSICAL_PAGE) == LX_ERROR) { return (LX_ERROR); } } if (lx_nand_driver_extra_bytes_get(block, page + i, spare_buffer + i * SPARE_BYTES_PER_PAGE, SPARE_BYTES_PER_PAGE) == LX_ERROR) { return (LX_ERROR); } } /* USER CODE END driver_pages_read */ return ret; } static UINT lx_nand_flash_driver_pages_write(ULONG block, ULONG page, UCHAR *main_buffer, UCHAR *spare_buffer, ULONG pages) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN driver_pages_write */ ULONG i; for (i = 0; i < pages; i++) { if (lx_nand_driver_write(block, page + i, (ULONG*)(main_buffer + i * BYTES_PER_PHYSICAL_PAGE), WORDS_PER_PHYSICAL_PAGE) == LX_ERROR) { return (LX_ERROR); } if (lx_nand_driver_extra_bytes_set(block, page + i, spare_buffer + i * SPARE_BYTES_PER_PAGE, SPARE_BYTES_PER_PAGE) == LX_ERROR) { return (LX_ERROR); } } /* USER CODE END driver_pages_write */ return ret; } static UINT lx_nand_flash_driver_pages_copy(ULONG source_block, ULONG source_page, ULONG destination_block, ULONG destination_page, ULONG pages, UCHAR *data_buffer) { UINT ret = LX_SUCCESS; /* USER CODE BEGIN driver_pages_copy */ ULONG i; for (i = 0; i < pages; i++) { if (lx_nand_flash_driver_pages_read(source_block, source_page + i, data_buffer , data_buffer + BYTES_PER_PHYSICAL_PAGE, 1) == LX_ERROR) { return (LX_ERROR); } if (lx_nand_flash_driver_pages_write(destination_block, destination_page + i, data_buffer , data_buffer + BYTES_PER_PHYSICAL_PAGE, 1) == LX_ERROR) { return (LX_ERROR); } } /* USER CODE END driver_pages_copy */ return ret; } /* Erase chip function*/ static UINT _lx_nand_flash_erase_all_driver(VOID) { if (W25NXX_ChipErase() != 1) { return (LX_ERROR); } return (LX_SUCCESS); } /* USER CODE END 1 */