Initial commit

This commit is contained in:
PProvost
2020-05-11 08:49:43 -06:00
commit 6f4ea0561f
65 changed files with 14775 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
.git* export-ignore
.hooks* export-ignore
# Custom attribute to mark sources as using our C code style.
[attr]our-c-style whitespace=tab-in-indent eol=lf format.clang-format-6.0
# Custom attribute to mark sources as generated.
# Do not perform whitespace checks. Do not format.
[attr]generated whitespace=-tab-in-indent,-indent-with-non-tab -format.clang-format-6.0
bootstrap eol=lf
configure eol=lf
*.[1-9] eol=lf
*.bash eol=lf
*.sh eol=lf
*.sh.in eol=lf
*.bat eol=crlf
*.bat.in eol=crlf
*.sln eol=crlf
*.vcproj eol=crlf
*.pfx -text
*.png -text
*.png.in -text
*.c our-c-style
*.cc our-c-style
*.cpp our-c-style
*.cu our-c-style
*.cxx our-c-style
*.h our-c-style
*.hh our-c-style
*.hpp our-c-style
*.hxx our-c-style
*.notcu our-c-style
*.cmake whitespace=tab-in-indent
*.rst whitespace=tab-in-indent conflict-marker-size=79
*.txt whitespace=tab-in-indent
+14
View File
@@ -0,0 +1,14 @@
.vscode/
_deps/
build/
CMakeFiles/
CMakeScripts/
CMakeLists.txt.user
CMakeCache.txt
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
+28
View File
@@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
# Set up the project
project(levelx
VERSION 6.0.0
LANGUAGES C ASM
)
if(NOT DEFINED THREADX_ARCH)
message(FATAL_ERROR "Error: THREADX_ARCH not defined")
endif()
if(NOT DEFINED THREADX_TOOLCHAIN)
message(FATAL_ERROR "Error: THREADX_TOOLCHAIN not defined")
endif()
# Define our target library and an alias for consumers
add_library(${PROJECT_NAME})
add_library("azrtos::${PROJECT_NAME}" ALIAS ${PROJECT_NAME})
# Define any required dependencies between this library and others
target_link_libraries(${PROJECT_NAME} PUBLIC
"azrtos::threadx"
)
# Pick up the common stuff
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/common)
+246
View File
@@ -0,0 +1,246 @@
MICROSOFT SOFTWARE LICENSE TERMS
MICROSOFT AZURE RTOS
Shape
These license terms are an agreement between you and Microsoft Corporation (or
one of its affiliates). They apply to the software named above and any Microsoft
services or software updates (except to the extent such services or updates are
accompanied by new or additional terms, in which case those different terms
apply prospectively and do not alter your or Microsofts rights relating to
pre-updated software or services). IF YOU COMPLY WITH THESE LICENSE TERMS, YOU
HAVE THE RIGHTS BELOW. BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS.
INSTALLATION AND USE RIGHTS.
General. You may install and use the software and the included Microsoft
applications solely for internal development, testing and evaluation purposes.
Any distribution or production use requires a separate license as set forth in
Section 2.
Contributions. Microsoft welcomes contributions to this software. In the event
that you make a contribution to this software you will be required to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and
actually do, grant Microsoft the rights to use your contribution. For details,
visit https://cla.microsoft.com.
Included Microsoft Applications. The software includes other Microsoft
applications which are governed by the licenses embedded in or made available
with those applications.
Third Party Components. The software may include third party components with
separate legal notices or governed by other agreements, as may be described
within the software or in the ThirdPartyNotices file(s) accompanying the
software.
Competitive Benchmarking. If you are a direct competitor, and you access or use
the software for purposes of competitive benchmarking, analysis, or intelligence
gathering, you waive as against Microsoft, its subsidiaries, and its affiliated
companies (including prospectively) any competitive use, access, and
benchmarking test restrictions in the terms governing your software to the
extent your terms of use are, or purport to be, more restrictive than
Microsofts terms. If you do not waive any such purported restrictions in the
terms governing your software, you are not allowed to access or use this
software, and will not do so.
DISTRIBUTION AND PRODUCTION USE. If you have obtained and/or are developing on
microprocessor(s) and/or microcontroller(s) (“hardware”) listed in the file
named “LICENSED-HARDWARE.txt” included in the repository and/or distributed with
the software you have the following rights in and to the software solely when
used in combination with the hardware. In the event hardware is not listed in
the LICENSED-HARDWARE.txt file, you do not have the rights in this Section 2.
Distribution and Production Use Rights.
You may use the software in production (e.g. program the modified or unmodified
software to devices you own or control) and distribute (i.e. make available to
third parties) the modified or unmodified binary image produced from this code.
You may permit your device distributors or developers to copy and distribute the
binary image as programmed or to be programmed to your devices.
You may redistribute the unmodified or modified source to your device
distributors or developers. Modifications must be clearly marked. Any
redistribution in source code form must contain this license and any other
licenses that accompany the software.
Requirements. For any code you distribute, you must:
when distributed in binary form, except as embedded in a device, include with
such distribution the terms of this agreement;
when distributed in source code form to distributors or developers of your
devices, include with such distribution the terms of this agreement; and
indemnify, defend and hold harmless Microsoft from any claims, including
attorneys fees, related to the distribution or use of your devices, except to
the extent that any claim is based solely on the unmodified software.
Restrictions. You may not:
use or modify the software to create a competing real time operating system
software;
remove any copyright notices or licenses contained in the software;
use Microsofts trademarks or trade dress in your application in any way that
suggests your device or application comes from or is endorsed by Microsoft;
transfer individual components, specific libraries, classes, functions or code
fragments of the software separately for purposes unrelated to the software; or
use or distribute the software in any way that would subject the software or
Microsofts intellectual property or technology to any other license terms.
SCOPE OF LICENSE. The software is licensed, not sold. Microsoft reserves all
other rights. Unless applicable law gives you more rights despite this
limitation, you will not (and have no right to):
remove, minimize, block, or modify any notices of Microsoft or its suppliers in
the software;
use the software in any way that is against the law or to create or propagate
malware; or
share, publish, distribute, or lease the software (except as permitted in
Section 2 above), or provide the software as a stand-alone offering for others
to use.
DATA. This software may interact with other Microsoft products that collect data
that is transmitted to Microsoft. To learn more about how Microsoft processes
personal data we collect, please see the Microsoft Privacy Statement at
https://go.microsoft.com/fwlink/?LinkId=248681.
EXPORT RESTRICTIONS. You must comply with all domestic and international export
laws and regulations that apply to the software, which include restrictions on
destinations, end users, and end use. For further information on export
restrictions, visit https://aka.ms/exporting.
SUPPORT SERVICES. Microsoft is not obligated under this agreement to provide any
support services for the software. Any support provided is “as is”, “with all
faults”, and without warranty of any kind.
UPDATES. Microsoft may periodically update the software. You may obtain updates
only from Microsoft or Microsoft-authorized sources. Updates may not include or
support all existing software features, services, or peripheral devices.
TERMINATION. Without prejudice to any other rights, Microsoft may terminate this
agreement if you fail to comply with any of its terms or conditions. In such
event, you must destroy all copies of the software and all of its component
parts.
ENTIRE AGREEMENT. This agreement, and any other terms Microsoft may provide for
supplements, updates, or third-party applications, is the entire agreement for
the software. To the extent you have entered into a separate agreement with
Microsoft relating specifically to the software, the terms in such agreement
shall control.
APPLICABLE LAW AND PLACE TO RESOLVE DISPUTES. If you acquired the software in
the United States or Canada, the laws of the state or province where you live
(or, if a business, where your principal place of business is located) govern
the interpretation of this agreement, claims for its breach, and all other
claims (including consumer protection, unfair competition, and tort claims),
regardless of conflict of laws principles. If you acquired the software in any
other country, its laws apply. If U.S. federal jurisdiction exists, you and
Microsoft consent to exclusive jurisdiction and venue in the federal court in
King County, Washington for all disputes heard in court. If not, you and
Microsoft consent to exclusive jurisdiction and venue in the Superior Court of
King County, Washington for all disputes heard in court.
CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal
rights. You may have other rights, including consumer rights, under the laws of
your state or country. Separate and apart from your relationship with Microsoft,
you may also have rights with respect to the party from which you acquired the
software. This agreement does not change those other rights if the laws of your
state or country do not permit it to do so. For example, if you acquired the
software in one of the below regions, or mandatory country law applies, then the
following provisions apply to you:
Australia. You have statutory guarantees under the Australian Consumer Law and
nothing in this agreement is intended to affect those rights.
Germany and Austria.
i.Warranty. The properly licensed software will perform substantially as
described in any Microsoft materials that accompany the software. However,
Microsoft gives no contractual guarantee in relation to the licensed software.
ii.Limitation of Liability. In case of intentional conduct, gross negligence,
claims based on the Product Liability Act, as well as, in case of death or
personal or physical injury, Microsoft is liable according to the statutory law.
Subject to the foregoing clause ii., Microsoft will only be liable for slight
negligence if Microsoft is in breach of such material contractual obligations,
the fulfillment of which facilitate the due performance of this agreement, the
breach of which would endanger the purpose of this agreement and the compliance
with which a party may constantly trust in (so-called "cardinal obligations").
In other cases of slight negligence, Microsoft will not be liable for slight
negligence.
DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS IS.” YOU BEAR THE RISK OF
USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES, OR CONDITIONS. TO
THE EXTENT PERMITTED UNDER APPLICABLE LAWS, MICROSOFT EXCLUDES ALL IMPLIED
WARRANTIES, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
NON-INFRINGEMENT.
LIMITATION ON AND EXCLUSION OF DAMAGES. IF YOU HAVE ANY BASIS FOR RECOVERING
DAMAGES DESPITE THE PRECEDING DISCLAIMER OF WARRANTY, YOU CAN RECOVER FROM
MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT
RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL,
INDIRECT, OR INCIDENTAL DAMAGES.
This limitation applies to (a) anything related to the software, services,
content (including code) on third party Internet sites, or third party
applications; and (b) claims for breach of contract, warranty, guarantee, or
condition; strict liability, negligence, or other tort; or any other claim; in
each case to the extent permitted by applicable law.
It also applies even if Microsoft knew or should have known about the
possibility of the damages. The above limitation or exclusion may not apply to
you because your state, province, or country may not allow the exclusion or
limitation of incidental, consequential, or other damages.
Please note: As this software is distributed in Canada, some of the clauses in
this agreement are provided below in French.
Remarque: Ce logiciel étant distribué au Canada, certaines des clauses dans ce
contrat sont fournies ci-dessous en français.
EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel
». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft
naccorde aucune autre garantie expresse. Vous pouvez bénéficier de droits
additionnels en vertu du droit local sur la protection des consommateurs, que ce
contrat ne peut modifier. La ou elles sont permises par le droit locale, les
garanties implicites de qualité marchande, dadéquation à un usage particulier
et dabsence de contrefaçon sont exclues.
LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES
DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une
indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous
ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris
les dommages spéciaux, indirects ou accessoires et pertes de bénéfices.
Cette limitation concerne:
•tout ce qui est relié au logiciel, aux services ou au contenu (y compris le
code) figurant sur des sites Internet tiers ou dans des programmes tiers; et
•les réclamations au titre de violation de contrat ou de garantie, ou au titre
de responsabilité stricte, de négligence ou dune autre faute dans la limite
autorisée par la loi en vigueur.
Elle sapplique également, même si Microsoft connaissait ou devrait connaître
l’éventualité dun tel dommage. Si votre pays nautorise pas lexclusion ou la
limitation de responsabilité pour les dommages indirects, accessoires ou de
quelque nature que ce soit, il se peut que la limitation ou lexclusion
ci-dessus ne sappliquera pas à votre égard.
EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous
pourriez avoir dautres droits prévus par les lois de votre pays. Le présent
contrat ne modifie pas les droits que vous confèrent les lois de votre pays si
celles-ci ne le permettent pas.
+16
View File
@@ -0,0 +1,16 @@
LICENSED HARDWARE LIST
Last Updated: 2020-05-08
Microsoft has entered into OEM Agreements with manufacturers of the following
microprocessors and microcontrollers (the “hardware”) to enable those
manufacturers to include and distribute Azure RTOS in certain hardware. If you
have obtained and/or are developing on microprocessor(s) and/or
microcontroller(s) (“hardware”) listed below you inherit the “Distribution and
Production Use” rights in Section 2 of the Microsoft Software License Terms for
Microsoft Azure RTOS. If hardware is not listed below, you do not have those
rights.
--------------------------------------------------------------------------------
More coming soon. Please check back frequently for updates.
+1
View File
@@ -0,0 +1 @@
# LevelX
+3
View File
@@ -0,0 +1,3 @@
TODO:
+63
View File
@@ -0,0 +1,63 @@
target_sources(${PROJECT_NAME} PRIVATE
# {{BEGIN_TARGET_SOURCES}}
${CMAKE_CURRENT_LIST_DIR}/src/fx_nand_flash_simulated_driver.c
${CMAKE_CURRENT_LIST_DIR}/src/fx_nor_flash_simulator_driver.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_256byte_ecc_check.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_256byte_ecc_compute.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_full_update.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_obsoleted_check.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_block_reclaim.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_close.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_defragment.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_block_erase.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_block_erased_verify.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_block_status_get.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_block_status_set.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_extra_bytes_get.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_extra_bytes_set.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_page_erased_verify.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_read.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_driver_write.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_extended_cache_enable.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_initialize.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_logical_sector_find.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_next_block_to_erase_find.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_open.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_page_ecc_check.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_page_ecc_compute.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_partial_defragment.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_physical_page_allocate.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sector_mapping_cache_invalidate.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sector_read.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sector_release.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_sector_write.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_simulator.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nand_flash_system_error.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_block_reclaim.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_close.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_defragment.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_driver_block_erase.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_driver_read.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_driver_write.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_extended_cache_enable.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_initialize.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_logical_sector_find.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_next_block_to_erase_find.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_open.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_partial_defragment.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_physical_sector_allocate.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_sector_mapping_cache_invalidate.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_sector_read.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_sector_release.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_sector_write.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_simulator.c
${CMAKE_CURRENT_LIST_DIR}/src/lx_nor_flash_system_error.c
# {{END_TARGET_SOURCES}}
)
# Add the Common/inc directory to the project include list
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_LIST_DIR}/inc
)
+530
View File
@@ -0,0 +1,530 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** Application Interface (API) */
/** */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/* */
/* APPLICATION INTERFACE DEFINITION RELEASE */
/* */
/* lx_api.h PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This file defines the basic Application Interface (API) to the */
/* high-performance LevelX. All service prototypes and data structure */
/* definitions are defined in this file. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
#ifndef LX_API_H
#define LX_API_H
/* Include necessary system files. */
#include "tx_api.h"
/* Disable warning of parameter not used. */
#ifndef LX_PARAMETER_NOT_USED
#define LX_PARAMETER_NOT_USED(p) ((void)(p))
#endif /* LX_PARAMETER_NOT_USED */
/* Define general LevelX Constants. */
#define LX_FALSE 0
#define LX_TRUE 1
#define LX_NULL 0
#define LX_BLOCK_ERASE_COUNT_MASK 0x7FFFFFFF
#define LX_BLOCK_ERASE_COUNT_MAX 0x7FFFFFFF
#define LX_BLOCK_ERASED 0x80000000
#define LX_BLOCK_ERASE_STARTED 0
#define LX_ALL_ONES 0xFFFFFFFF
/* Define error codes. */
#define LX_SUCCESS 0
#define LX_ERROR 1
#define LX_NO_SECTORS 2
#define LX_SECTOR_NOT_FOUND 3
#define LX_NO_PAGES 4
#define LX_INVALID_WRITE 5
#define LX_NAND_ERROR_CORRECTED 6
#define LX_NAND_ERROR_NOT_CORRECTED 7
#define LX_NO_MEMORY 8
#define LX_DISABLED 9
#define LX_SYSTEM_INVALID_FORMAT 90
#define LX_SYSTEM_INVALID_BLOCK 91
#define LX_SYSTEM_ALLOCATION_FAILED 92
#define LX_SYSTEM_MUTEX_CREATE_FAILED 93
#define LX_SYSTEM_INVALID_SECTOR_MAP 94
/* Define NOR flash constants. */
#define LX_NOR_FLASH_OPENED ((ULONG) 0x4E4F524F)
#define LX_NOR_FLASH_CLOSED ((ULONG) 0x4E4F5244)
#define LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))
#define LX_NOR_FLASH_MIN_LOGICAL_SECTOR_OFFSET 1
#define LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET 2
#ifndef LX_NOR_FLASH_MAX_ERASE_COUNT_DELTA
#define LX_NOR_FLASH_MAX_ERASE_COUNT_DELTA 4
#endif
#define LX_NOR_SECTOR_MAPPING_CACHE_DEPTH 4
#ifndef LX_NOR_SECTOR_MAPPING_CACHE_SIZE
#define LX_NOR_SECTOR_MAPPING_CACHE_SIZE 16 /* Minimum value of 8, all sizes must be a power of 2. */
#endif
#ifndef LX_NOR_EXTENDED_CACHE_SIZE
#define LX_NOR_EXTENDED_CACHE_SIZE 8 /* Maximum number of extended cache sectors. */
#endif
/* Define the mask for the hash index into the sector mapping cache table. The sector mapping cache is divided
into 4 entry pieces that are indexed by the formula:
index = (sector & LX_NOR_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NOR_SECTOR_MAPPING_CACHE_DEPTH
The LX_NOR_SECTOR_MAPPING_CACHE_DEPTH define must not be changed unless the related source code is also changed. */
#define LX_NOR_SECTOR_MAPPING_CACHE_HASH_MASK ((LX_NOR_SECTOR_MAPPING_CACHE_SIZE/LX_NOR_SECTOR_MAPPING_CACHE_DEPTH)-1)
#define LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_MASK 0x7FFFFFFF
#define LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID 0x80000000
#define LX_NOR_PHYSICAL_SECTOR_VALID 0x80000000
#define LX_NOR_PHYSICAL_SECTOR_SUPERCEDED 0x40000000
#define LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID 0x20000000
#define LX_NOR_LOGICAL_SECTOR_MASK 0x1FFFFFFF
#define LX_NOR_PHYSICAL_SECTOR_FREE 0xFFFFFFFF
/* Define NAND flash constants. */
#define LX_NAND_GOOD_BLOCK 0xFF
#define LX_NAND_BAD_BLOCK 0x00
#define LX_NAND_FLASH_OPENED ((ULONG) 0x4E4F524F)
#define LX_NAND_FLASH_CLOSED ((ULONG) 0x4E4F5244)
#ifndef LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA
#define LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA 64
#endif
/* Define the NAND sector mapping cache. */
#define LX_NAND_SECTOR_MAPPING_CACHE_DEPTH 4 /* Not required if LX_NAND_FLASH_DIRECT_MAPPING_CACHE is defined. */
#ifndef LX_NAND_SECTOR_MAPPING_CACHE_SIZE
#define LX_NAND_SECTOR_MAPPING_CACHE_SIZE 128 /* Minimum value of 8, all sizes must be a power of 2, unless direct
mapping is defined, in which there is no power of 2 requirement. */
#endif
#ifndef LX_NAND_ERASE_COUNT_WRITE_SIZE
#define LX_NAND_ERASE_COUNT_WRITE_SIZE (nand_flash -> lx_nand_flash_pages_per_block + 1)
#endif
/* Define the mask for the hash index into the NAND sector mapping cache table. The sector mapping cache is divided
into 4 entry pieces that are indexed by the formula:
index = (sector & LX_NAND_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NAND_SECTOR_MAPPING_CACHE_DEPTH
The LX_NAND_SECTOR_MAPPING_CACHE_DEPTH define must not be changed unless the related source code is also changed. */
#define LX_NAND_SECTOR_MAPPING_CACHE_HASH_MASK ((LX_NAND_SECTOR_MAPPING_CACHE_SIZE/LX_NAND_SECTOR_MAPPING_CACHE_DEPTH)-1)
#define LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_MASK 0x7FFFFFFF
#define LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID 0x80000000
#define LX_NAND_BLOCK_VALID 0x80000000
#define LX_NAND_BLOCK_EMPTY 0x40000000
#define LX_NAND_BLOCK_FULL 0x20000000
#define LX_NAND_PAGE_VALID 0x80000000
#define LX_NAND_PAGE_SUPERCEDED 0x40000000
#define LX_NAND_PAGE_MAPPING_NOT_VALID 0x20000000
#define LX_NAND_LOGICAL_SECTOR_MASK 0x1FFFFFFF
#define LX_NAND_PAGE_FREE 0xFFFFFFFF
#define LX_NAND_PAGE_LIST_VALID 0xF0F0F0F0
/* Define the NAND flash extra byte structure. This will be set in the spare area of each mapped physical page. */
typedef struct LX_NAND_PAGE_EXTRA_INFO_STRUCT
{
ULONG lx_nand_page_extra_info_logical_sector;
} LX_NAND_PAGE_EXTRA_INFO;
/* Define the NAND flash logical sector cache entry structure. */
typedef struct LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_STRUCT
{
#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
ULONG lx_nand_sector_mapping_cache_logical_sector;
#endif
USHORT lx_nand_sector_mapping_cache_block;
USHORT lx_nand_sector_mapping_cache_page;
} LX_NAND_SECTOR_MAPPING_CACHE_ENTRY;
/* Define the NAND flash control block structure. */
typedef struct LX_NAND_FLASH_STRUCT
{
ULONG lx_nand_flash_state;
ULONG lx_nand_flash_total_blocks;
ULONG lx_nand_flash_pages_per_block;
ULONG lx_nand_flash_bytes_per_page;
ULONG lx_nand_flash_words_per_block;
ULONG lx_nand_flash_words_per_page;
ULONG lx_nand_flash_total_pages;
ULONG lx_nand_flash_bad_blocks;
ULONG lx_nand_flash_free_pages;
ULONG lx_nand_flash_mapped_pages;
ULONG lx_nand_flash_obsolete_pages;
ULONG lx_nand_flash_minimum_erase_count;
ULONG lx_nand_flash_maximum_erase_count;
ULONG lx_nand_flash_free_block_search;
ULONG lx_nand_flash_found_block_search;
ULONG lx_nand_flash_found_page_search;
ULONG lx_nand_flash_max_mapped_sector;
ULONG lx_nand_flash_page_corrections;
ULONG lx_nand_flash_last_block_correction;
ULONG lx_nand_flash_last_page_correction;
ULONG lx_nand_flash_diagnostic_system_errors;
ULONG lx_nand_flash_diagnostic_system_error;
ULONG lx_nand_flash_diagnostic_sector_write_requests;
ULONG lx_nand_flash_diagnostic_sector_read_requests;
ULONG lx_nand_flash_diagnostic_sector_release_requests;
ULONG lx_nand_flash_diagnostic_page_allocates;
ULONG lx_nand_flash_diagnostic_page_allocate_errors;
ULONG lx_nand_flash_diagnostic_sector_mapping_cache_hits;
ULONG lx_nand_flash_diagnostic_sector_mapping_cache_misses;
ULONG lx_nand_flash_diagnostic_page_extra_bytes_cache_hits;
ULONG lx_nand_flash_diagnostic_page_extra_bytes_cache_misses;
ULONG lx_nand_flash_diagnostic_page_0_cache_hits;
ULONG lx_nand_flash_diagnostic_page_0_cache_misses;
ULONG lx_nand_flash_diagnostic_block_status_cache_hits;
ULONG lx_nand_flash_diagnostic_block_status_cache_misses;
ULONG lx_nand_flash_diagnostic_block_reclaim_attempts;
ULONG lx_nand_flash_diagnostic_block_erases;
ULONG lx_nand_flash_diagnostic_block_status_gets;
ULONG lx_nand_flash_diagnostic_block_status_sets;
ULONG lx_nand_flash_diagnostic_page_extra_bytes_sets;
ULONG lx_nand_flash_diagnostic_page_writes;
ULONG lx_nand_flash_diagnostic_page_extra_bytes_gets;
ULONG lx_nand_flash_diagnostic_page_reads;
ULONG lx_nand_flash_diagnostic_moved_pages;
ULONG lx_nand_flash_diagnostic_block_erased_verifies;
ULONG lx_nand_flash_diagnostic_page_erased_verifies;
ULONG lx_nand_flash_diagnostic_initial_format;
ULONG lx_nand_flash_diagnostic_erased_block;
ULONG lx_nand_flash_diagnostic_re_erase_block;
ULONG lx_nand_flash_diagnostic_page_being_obsoleted;
ULONG lx_nand_flash_diagnostic_page_obsoleted;
ULONG lx_nand_flash_diagnostic_mapping_invalid;
ULONG lx_nand_flash_diagnostic_mapping_write_interrupted;
ULONG lx_nand_flash_diagnostic_page_not_free;
ULONG lx_nand_flash_diagnostic_page_data_not_free;
UINT (*lx_nand_flash_driver_read)(ULONG block, ULONG page, ULONG *destination, ULONG words);
UINT (*lx_nand_flash_driver_write)(ULONG block, ULONG page, ULONG *source, ULONG words);
UINT (*lx_nand_flash_driver_block_erase)(ULONG block, ULONG erase_count);
UINT (*lx_nand_flash_driver_block_erased_verify)(ULONG block);
UINT (*lx_nand_flash_driver_page_erased_verify)(ULONG block, ULONG page);
UINT (*lx_nand_flash_driver_block_status_get)(ULONG block, UCHAR *bad_block_flag);
UINT (*lx_nand_flash_driver_block_status_set)(ULONG block, UCHAR bad_block_flag);
UINT (*lx_nand_flash_driver_extra_bytes_get)(ULONG block, ULONG page, UCHAR *destination, UINT size);
UINT (*lx_nand_flash_driver_extra_bytes_set)(ULONG block, ULONG page, UCHAR *source, UINT size);
UINT (*lx_nand_flash_driver_system_error)(UINT error_code, ULONG block, ULONG page);
ULONG *lx_nand_flash_page_buffer;
UINT lx_nand_flash_sector_mapping_cache_enabled;
LX_NAND_SECTOR_MAPPING_CACHE_ENTRY
lx_nand_flash_sector_mapping_cache[LX_NAND_SECTOR_MAPPING_CACHE_SIZE];
/* Define the extended cache structures for block status, page extra bytes, and block page 0 caches. The memory for these cache
extensions is optionally supplied by the application after the lx_nand_flash_open call has been made. */
UCHAR *lx_nand_flash_block_status_cache;
LX_NAND_PAGE_EXTRA_INFO *lx_nand_flash_page_extra_bytes_cache;
ULONG *lx_nand_flash_page_0_cache;
#ifdef LX_THREAD_SAFE_ENABLE
/* When this conditional is used, the LevelX code utilizes a ThreadX mutex for thread
safe operation. Generally, this is not required since FileX ensures thread safe operation at
a higher layer. */
TX_MUTEX lx_nand_flash_mutex;
#endif
/* Define the NAND flash control block open next/previous pointers. */
struct LX_NAND_FLASH_STRUCT *lx_nand_flash_open_next,
*lx_nand_flash_open_previous;
} LX_NAND_FLASH;
/* Define the NOR flash sector cache entry structure. */
typedef struct LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_STRUCT
{
ULONG lx_nor_sector_mapping_cache_logical_sector;
ULONG *lx_nor_sector_mapping_cache_physical_sector_map_entry;
ULONG *lx_nor_sector_mapping_cache_physical_sector_address;
} LX_NOR_SECTOR_MAPPING_CACHE_ENTRY;
/* Define the NOR flash extended cache entry structure. */
typedef struct LX_NOR_FLASH_EXTENDED_CACHE_ENTRY_STRUCT
{
ULONG *lx_nor_flash_extended_cache_entry_sector_address;
ULONG *lx_nor_flash_extended_cache_entry_sector_memory;
ULONG lx_nor_flash_extended_cache_entry_access_count;
} LX_NOR_FLASH_EXTENDED_CACHE_ENTRY;
/* Define the NOR flash control block structure. */
typedef struct LX_NOR_FLASH_STRUCT
{
ULONG lx_nor_flash_state;
ULONG lx_nor_flash_total_blocks;
ULONG lx_nor_flash_words_per_block;
ULONG lx_nor_flash_total_physical_sectors;
ULONG lx_nor_flash_physical_sectors_per_block;
ULONG *lx_nor_flash_base_address;
ULONG lx_nor_flash_block_free_bit_map_offset;
ULONG lx_nor_flash_block_bit_map_words;
ULONG lx_nor_flash_block_bit_map_mask;
ULONG lx_nor_flash_block_physical_sector_mapping_offset;
ULONG lx_nor_flash_block_physical_sector_offset;
ULONG lx_nor_flash_free_physical_sectors;
ULONG lx_nor_flash_mapped_physical_sectors;
ULONG lx_nor_flash_obsolete_physical_sectors;
ULONG lx_nor_flash_minimum_erase_count;
ULONG lx_nor_flash_maximum_erase_count;
ULONG lx_nor_flash_free_block_search;
ULONG lx_nor_flash_found_block_search;
ULONG lx_nor_flash_found_sector_search;
ULONG lx_nor_flash_write_requests;
ULONG lx_nor_flash_read_requests;
ULONG lx_nor_flash_sector_mapping_cache_hits;
ULONG lx_nor_flash_sector_mapping_cache_misses;
ULONG lx_nor_flash_physical_block_allocates;
ULONG lx_nor_flash_physical_block_allocate_errors;
ULONG lx_nor_flash_diagnostic_system_errors;
ULONG lx_nor_flash_diagnostic_system_error;
ULONG lx_nor_flash_diagnostic_initial_format;
ULONG lx_nor_flash_diagnostic_erased_block;
ULONG lx_nor_flash_diagnostic_re_erase_block;
ULONG lx_nor_flash_diagnostic_sector_being_obsoleted;
ULONG lx_nor_flash_diagnostic_sector_obsoleted;
ULONG lx_nor_flash_diagnostic_mapping_invalidated;
ULONG lx_nor_flash_diagnostic_mapping_write_interrupted;
ULONG lx_nor_flash_diagnostic_sector_not_free;
ULONG lx_nor_flash_diagnostic_sector_data_not_free;
UINT (*lx_nor_flash_driver_read)(ULONG *flash_address, ULONG *destination, ULONG words);
UINT (*lx_nor_flash_driver_write)(ULONG *flash_address, ULONG *source, ULONG words);
UINT (*lx_nor_flash_driver_block_erase)(ULONG block, ULONG erase_count);
UINT (*lx_nor_flash_driver_block_erased_verify)(ULONG block);
UINT (*lx_nor_flash_driver_system_error)(UINT error_code);
ULONG *lx_nor_flash_sector_buffer;
UINT lx_nor_flash_sector_mapping_cache_enabled;
LX_NOR_SECTOR_MAPPING_CACHE_ENTRY
lx_nor_flash_sector_mapping_cache[LX_NOR_SECTOR_MAPPING_CACHE_SIZE];
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
UINT lx_nor_flash_extended_cache_entries;
LX_NOR_FLASH_EXTENDED_CACHE_ENTRY
lx_nor_flash_extended_cache[LX_NOR_EXTENDED_CACHE_SIZE];
ULONG lx_nor_flash_extended_cache_hits;
ULONG lx_nor_flash_extended_cache_misses;
#endif
#ifdef LX_THREAD_SAFE_ENABLE
/* When this conditional is used, the LevelX code utilizes a ThreadX mutex for thread
safe operation. Generally, this is not required since FileX ensures thread safe operation at
a higher layer. */
TX_MUTEX lx_nor_flash_mutex;
#endif
/* Define the NOR flash control block open next/previous pointers. */
struct LX_NOR_FLASH_STRUCT *lx_nor_flash_open_next,
*lx_nor_flash_open_previous;
} LX_NOR_FLASH;
/* Each physical NOR block has the following structure at the beginning of the block:
Offset Meaning
0 Erase count
4 Minimum logical sector number - only when the block is full
8 Maximum logical sector number - only when the block is full
12 Free physical sector bit map, where a value of 1 indicates a
free physical sector. The bit map is evenly divisible by 4
. Array of physical sector mapping information (4 bytes per entry,
one entry for each physical sector in block). Each entry looks
like the following:
Bit(s) Meaning
0-29 Logical sector mapped if not 0x3FFFFFFF
30 If 0, entry is being superceded
31 If 1, entry is valid
Array of physical sectors, with each of size LX_NOR_SECTOR_SIZE
*/
typedef struct LX_NOR_FLASH_BLOCK_HEADER_STRUCT
{
ULONG lx_nor_flash_block_erase_count; /* Bit 31: 1 -> not used, 0 -> used */
ULONG lx_nor_flash_block_min_logical_sector; /* On full block, minimum valid sector */
ULONG lx_nor_flash_block_max_logical_sector; /* On full block, maximum valid sector */
} LX_NOR_FLASH_BLOCK_HEADER;
/* Define external structure references. */
extern LX_NAND_FLASH *_lx_nand_flash_opened_ptr;
extern ULONG _lx_nand_flash_opened_count;
extern LX_NOR_FLASH *_lx_nor_flash_opened_ptr;
extern ULONG _lx_nor_flash_opened_count;
/* Map internal functions. */
#ifndef LX_SOURCE_CODE
#define lx_nand_flash_close _lx_nand_flash_close
#define lx_nand_flash_defragment _lx_nand_flash_defragment
#define lx_nand_flash_partial_defragment _lx_nand_flash_partial_defragment
#define lx_nand_flash_extended_cache_enable _lx_nand_flash_extended_cache_enable
#define lx_nand_flash_initialize _lx_nand_flash_initialize
#define lx_nand_flash_open _lx_nand_flash_open
#define lx_nand_flash_page_ecc_check _lx_nand_flash_page_ecc_check
#define lx_nand_flash_page_ecc_compute _lx_nand_flash_page_ecc_compute
#define lx_nand_flash_sector_read _lx_nand_flash_sector_read
#define lx_nand_flash_sector_release _lx_nand_flash_sector_release
#define lx_nand_flash_sector_write _lx_nand_flash_sector_write
#define lx_nand_flash_256byte_ecc_check _lx_nand_flash_256byte_ecc_check
#define lx_nand_flash_256byte_ecc_compute _lx_nand_flash_256byte_ecc_compute
#define lx_nor_flash_close _lx_nor_flash_close
#define lx_nor_flash_defragment _lx_nor_flash_defragment
#define lx_nor_flash_partial_defragment _lx_nor_flash_partial_defragment
#define lx_nor_flash_extended_cache_enable _lx_nor_flash_extended_cache_enable
#define lx_nor_flash_initialize _lx_nor_flash_initialize
#define lx_nor_flash_open _lx_nor_flash_open
#define lx_nor_flash_sector_read _lx_nor_flash_sector_read
#define lx_nor_flash_sector_release _lx_nor_flash_sector_release
#define lx_nor_flash_sector_write _lx_nor_flash_sector_write
#endif
/* External LevelX API prototypes. */
UINT _lx_nand_flash_close(LX_NAND_FLASH *nand_flash);
UINT _lx_nand_flash_defragment(LX_NAND_FLASH *nand_flash);
UINT _lx_nand_flash_initialize(void);
UINT _lx_nand_flash_extended_cache_enable(LX_NAND_FLASH *nand_flash, VOID *memory, ULONG size);
UINT _lx_nand_flash_open(LX_NAND_FLASH *nand_flash, CHAR *name, UINT (*nand_driver_initialize)(LX_NAND_FLASH *));
UINT _lx_nand_flash_page_ecc_check(LX_NAND_FLASH *nand_flash, UCHAR *page_buffer, UCHAR *ecc_buffer);
UINT _lx_nand_flash_page_ecc_compute(LX_NAND_FLASH *nand_flash, UCHAR *page_buffer, UCHAR *ecc_buffer);
UINT _lx_nand_flash_partial_defragment(LX_NAND_FLASH *nand_flash, UINT max_blocks);
UINT _lx_nand_flash_sector_read(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer);
UINT _lx_nand_flash_sector_release(LX_NAND_FLASH *nand_flash, ULONG logical_sector);
UINT _lx_nand_flash_sector_write(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer);
UINT _lx_nor_flash_close(LX_NOR_FLASH *nor_flash);
UINT _lx_nor_flash_defragment(LX_NOR_FLASH *nor_flash);
UINT _lx_nor_flash_extended_cache_enable(LX_NOR_FLASH *nor_flash, VOID *memory, ULONG size);
UINT _lx_nor_flash_initialize(void);
UINT _lx_nor_flash_open(LX_NOR_FLASH *nor_flash, CHAR *name, UINT (*nor_driver_initialize)(LX_NOR_FLASH *));
UINT _lx_nor_flash_partial_defragment(LX_NOR_FLASH *nor_flash, UINT max_blocks);
UINT _lx_nor_flash_sector_read(LX_NOR_FLASH *nor_flash, ULONG logical_sector, VOID *buffer);
UINT _lx_nor_flash_sector_release(LX_NOR_FLASH *nor_flash, ULONG logical_sector);
UINT _lx_nor_flash_sector_write(LX_NOR_FLASH *nor_flash, ULONG logical_sector, VOID *buffer);
/* Internal LevelX prototypes. */
UINT _lx_nand_flash_block_full_update(LX_NAND_FLASH *nand_flash, ULONG block, ULONG erase_count);
VOID _lx_nand_flash_block_obsoleted_check(LX_NAND_FLASH *nand_flash, ULONG block);
UINT _lx_nand_flash_block_reclaim(LX_NAND_FLASH *nand_flash);
UINT _lx_nand_flash_driver_read(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *destination, ULONG words);
UINT _lx_nand_flash_driver_write(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *source, ULONG words);
UINT _lx_nand_flash_driver_block_erase(LX_NAND_FLASH *nand_flash, ULONG block, ULONG erase_count);
UINT _lx_nand_flash_driver_block_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block);
UINT _lx_nand_flash_driver_page_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page);
UINT _lx_nand_flash_driver_block_status_get(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR *bad_block_flag);
UINT _lx_nand_flash_driver_block_status_set(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR bad_block_flag);
UINT _lx_nand_flash_driver_extra_bytes_get(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *destination, UINT size);
UINT _lx_nand_flash_driver_extra_bytes_set(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *source, UINT size);
VOID _lx_nand_flash_internal_error(LX_NAND_FLASH *nand_flash, ULONG error_code);
UINT _lx_nand_flash_logical_sector_find(LX_NAND_FLASH *nand_flash, ULONG logical_sector, ULONG superceded_check, ULONG *block, ULONG *page);
UINT _lx_nand_flash_next_block_to_erase_find(LX_NAND_FLASH *nand_flash, ULONG *return_erase_block, ULONG *return_erase_count, ULONG *return_mapped_pages, ULONG *return_obsolete_pages);
UINT _lx_nand_flash_physical_page_allocate(LX_NAND_FLASH *nand_flash, ULONG *block, ULONG *page, ULONG *erase_count);
VOID _lx_nand_flash_sector_mapping_cache_invalidate(LX_NAND_FLASH *nand_flash, ULONG logical_sector);
VOID _lx_nand_flash_system_error(LX_NAND_FLASH *nand_flash, UINT error_code, ULONG block, ULONG page);
UINT _lx_nand_flash_256byte_ecc_check(UCHAR *page_buffer, UCHAR *ecc_buffer);
UINT _lx_nand_flash_256byte_ecc_compute(UCHAR *page_buffer, UCHAR *ecc_buffer);
UINT _lx_nor_flash_block_reclaim(LX_NOR_FLASH *nor_flash);
UINT _lx_nor_flash_driver_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count);
UINT _lx_nor_flash_driver_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words);
UINT _lx_nor_flash_driver_write(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *source, ULONG words);
VOID _lx_nor_flash_internal_error(LX_NOR_FLASH *nor_flash, ULONG error_code);
UINT _lx_nor_flash_logical_sector_find(LX_NOR_FLASH *nor_flash, ULONG logical_sector, ULONG superceded_check, ULONG **physical_sector_map_entry, ULONG **physical_sector_address);
UINT _lx_nor_flash_next_block_to_erase_find(LX_NOR_FLASH *nor_flash, ULONG *return_erase_block, ULONG *return_erase_count, ULONG *return_mapped_sectors, ULONG *return_obsolete_sectors);
UINT _lx_nor_flash_physical_sector_allocate(LX_NOR_FLASH *nor_flash, ULONG logical_sector, ULONG **physical_sector_map_entry, ULONG **physical_sector_address);
VOID _lx_nor_flash_sector_mapping_cache_invalidate(LX_NOR_FLASH *nor_flash, ULONG logical_sector);
VOID _lx_nor_flash_system_error(LX_NOR_FLASH *nor_flash, UINT error_code);
#endif
+441
View File
@@ -0,0 +1,441 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** FileX NAND FLASH Simulator Driver */
/** */
/**************************************************************************/
/**************************************************************************/
/* Include necessary system files. */
#include "tx_api.h"
#include "fx_api.h"
#include "lx_api.h"
/* Create a NAND flash control block. */
LX_NAND_FLASH nand_flash;
/* Define the NAND flash simulation initialization function. */
UINT _lx_nand_flash_simulator_initialize(LX_NAND_FLASH *nand_flash);
VOID _fx_nand_flash_read_sectors(ULONG logical_sector, ULONG sectors, UCHAR *destination_buffer);
VOID _fx_nand_flash_write_sectors(ULONG logical_sector, ULONG sectors, UCHAR *source_buffer);
/* The simulated NAND driver relies on the fx_media_format call to be made prior to
the fx_media_open call.
fx_media_format(&ram_disk,
_fx_nand_sim_driver, // Driver entry
FX_NULL, // Unused
media_memory, // Media buffer pointer
sizeof(media_memory), // Media buffer size
"MY_NAND_DISK", // Volume Name
1, // Number of FATs
32, // Directory Entries
0, // Hidden sectors
120, // Total sectors
2048, // Sector size
1, // Sectors per cluster
1, // Heads
1); // Sectors per track
*/
VOID _fx_nand_flash_simulator_driver(FX_MEDIA *media_ptr);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_nand_simulator_driver PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is the entry point to the generic NAND simulated */
/* disk driver that is delivered with the flash wear leveling product */
/* LevelX. */
/* */
/* This driver also serves as a template for developing other LevelX */
/* NAND flash drivers for actual flash devices. Simply replace the */
/* read/write sector logic with calls to read/write from the */
/* appropriate physical device access functions. */
/* */
/* FileX NAND FLASH structures look like the following: */
/* */
/* Logical Sector Contents */
/* */
/* 0 Boot record */
/* 1 FAT Area Start */
/* +FAT Sectors Root Directory Start */
/* +Directory Sectors Data Sector Start */
/* */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_close Close NAND flash manager */
/* _lx_nand_flash_open Open NAND flash manager */
/* _lx_nand_flash_sector_read Read a NAND sector */
/* _lx_nand_flash_sector_release Release a NAND sector */
/* _lx_nand_flash_sector_write Write a NAND sector */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
VOID _fx_nand_flash_simulator_driver(FX_MEDIA *media_ptr)
{
ULONG logical_sector;
ULONG count;
UCHAR *buffer;
UINT status;
/* There are several useful/important pieces of information contained in the media
structure, some of which are supplied by FileX and others are for the driver to
setup. The following is a summary of the necessary FX_MEDIA structure members:
FX_MEDIA Member Meaning
fx_media_driver_request FileX request type. Valid requests from FileX are
as follows:
FX_DRIVER_READ
FX_DRIVER_WRITE
FX_DRIVER_FLUSH
FX_DRIVER_ABORT
FX_DRIVER_INIT
FX_DRIVER_BOOT_READ
FX_DRIVER_RELEASE_SECTORS
FX_DRIVER_BOOT_WRITE
FX_DRIVER_UNINIT
fx_media_driver_status This value is RETURNED by the driver. If the
operation is successful, this field should be
set to FX_SUCCESS for before returning. Otherwise,
if an error occurred, this field should be set
to FX_IO_ERROR.
fx_media_driver_buffer Pointer to buffer to read or write sector data.
This is supplied by FileX.
fx_media_driver_logical_sector Logical sector FileX is requesting.
fx_media_driver_sectors Number of sectors FileX is requesting.
The following is a summary of the optional FX_MEDIA structure members:
FX_MEDIA Member Meaning
fx_media_driver_info Pointer to any additional information or memory.
This is optional for the driver use and is setup
from the fx_media_open call. The RAM disk uses
this pointer for the RAM disk memory itself.
fx_media_driver_write_protect The DRIVER sets this to FX_TRUE when media is write
protected. This is typically done in initialization,
but can be done anytime.
fx_media_driver_free_sector_update The DRIVER sets this to FX_TRUE when it needs to
know when clusters are released. This is important
for FLASH wear-leveling drivers.
fx_media_driver_system_write FileX sets this flag to FX_TRUE if the sector being
written is a system sector, e.g., a boot, FAT, or
directory sector. The driver may choose to use this
to initiate error recovery logic for greater fault
tolerance.
fx_media_driver_data_sector_read FileX sets this flag to FX_TRUE if the sector(s) being
read are file data sectors, i.e., NOT system sectors.
fx_media_driver_sector_type FileX sets this variable to the specific type of
sector being read or written. The following sector
types are identified:
FX_UNKNOWN_SECTOR
FX_BOOT_SECTOR
FX_FAT_SECTOR
FX_DIRECTORY_SECTOR
FX_DATA_SECTOR
*/
/* Process the driver request specified in the media control block. */
switch(media_ptr -> fx_media_driver_request)
{
case FX_DRIVER_READ:
{
/* Read sector(s) from NAND flash. */
logical_sector = media_ptr -> fx_media_driver_logical_sector;
count = media_ptr -> fx_media_driver_sectors;
buffer = (UCHAR *) media_ptr -> fx_media_driver_buffer;
while (count)
{
/* Call LevelX to read one flash sector. */
status = _lx_nand_flash_sector_read(&nand_flash, logical_sector, buffer);
/* Determine if the read was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful sector read. */
count--;
logical_sector++;
buffer += media_ptr -> fx_media_bytes_per_sector;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_WRITE:
{
/* Write sector(s) to NAND flash. */
logical_sector = media_ptr -> fx_media_driver_logical_sector;
count = media_ptr -> fx_media_driver_sectors;
buffer = (UCHAR *) media_ptr -> fx_media_driver_buffer;
while (count)
{
/* Call LevelX to write a sector. */
status = _lx_nand_flash_sector_write(&nand_flash, logical_sector, buffer);
/* Determine if the write was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful sector write. */
count--;
logical_sector++;
buffer += media_ptr -> fx_media_bytes_per_sector;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_RELEASE_SECTORS:
{
/* Release the mapping of this sector. */
logical_sector = media_ptr -> fx_media_driver_logical_sector;
count = media_ptr -> fx_media_driver_sectors;
while (count)
{
/* Call LevelX to release a sector mapping. */
status = _lx_nand_flash_sector_release(&nand_flash, logical_sector);
/* Determine if the sector release was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful sector release. */
count--;
logical_sector++;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_FLUSH:
{
/* Return driver success. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_ABORT:
{
/* Return driver success. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_INIT:
{
/* FLASH drivers are responsible for setting several fields in the
media structure, as follows:
media_ptr -> fx_media_driver_free_sector_update
media_ptr -> fx_media_driver_write_protect
The fx_media_driver_free_sector_update flag is used to instruct
FileX to inform the driver whenever sectors are not being used.
This is especially useful for FLASH managers so they don't have
maintain mapping for sectors no longer in use.
The fx_media_driver_write_protect flag can be set anytime by the
driver to indicate the media is not writable. Write attempts made
when this flag is set are returned as errors. */
/* Perform basic initialization here... since the boot record is going
to be read subsequently and again for volume name requests. */
/* With flash wear leveling, FileX should tell wear leveling when sectors
are no longer in use. */
media_ptr -> fx_media_driver_free_sector_update = FX_TRUE;
/* Open the NAND flash simulation. */
status = _lx_nand_flash_open(&nand_flash, "sim nand flash", _lx_nand_flash_simulator_initialize);
/* Determine if the flash open was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_UNINIT:
{
/* There is nothing to do in this case for the RAM driver. For actual
devices some shutdown processing may be necessary. */
/* Close the NAND flash simulation. */
status = _lx_nand_flash_close(&nand_flash);
/* Determine if the flash close was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_READ:
{
/* Read the boot record and return to the caller. */
status = _lx_nand_flash_sector_read(&nand_flash, 0, (UCHAR *) media_ptr -> fx_media_driver_buffer);
/* Determine if the read was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_WRITE:
{
/* Write the boot record and return to the caller. */
status = _lx_nand_flash_sector_write(&nand_flash, 0, (UCHAR *) media_ptr -> fx_media_driver_buffer);
/* Determine if the write was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break ;
}
default:
{
/* Invalid driver request. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
break;
}
}
}
+460
View File
@@ -0,0 +1,460 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** FileX NOR FLASH Simulator Driver */
/** */
/**************************************************************************/
/**************************************************************************/
/* Include necessary system files. */
#include "tx_api.h"
#include "fx_api.h"
#include "lx_api.h"
/* Create a NOR flash control block. */
LX_NOR_FLASH nor_flash;
/* The simulated NOR driver relies on the fx_media_format call to be made prior to
the fx_media_open call.
fx_media_format(&ram_disk,
_fx_nor_sim_driver, // Driver entry
FX_NULL, // Unused
media_memory, // Media buffer pointer
sizeof(media_memory), // Media buffer size
"MY_NOR_DISK", // Volume Name
1, // Number of FATs
32, // Directory Entries
0, // Hidden sectors
120, // Total sectors
512, // Sector size
1, // Sectors per cluster
1, // Heads
1); // Sectors per track
*/
/* Define prototypes. */
UINT _lx_nor_flash_simulator_initialize(LX_NOR_FLASH *nor_flash);
VOID _fx_nor_flash_simulator_driver(FX_MEDIA *media_ptr);
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_nor_flash_simulator_driver PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is the entry point to the generic NOR simulated */
/* disk driver that is delivered with the flash wear leveling product */
/* LevelX. */
/* */
/* This driver also serves as a template for developing other LevelX */
/* NOR flash drivers for actual flash devices. Simply replace the */
/* read/write sector logic with calls to read/write from the */
/* appropriate physical device access functions. */
/* */
/* FileX NOR FLASH structures look like the following: */
/* */
/* Logical Sector Contents */
/* */
/* 0 Boot record */
/* 1 FAT Area Start */
/* +FAT Sectors Root Directory Start */
/* +Directory Sectors Data Sector Start */
/* */
/* */
/* INPUT */
/* */
/* media_ptr Media control block pointer */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* lx_nor_flash_close Close NOR flash manager */
/* lx_nor_flash_open Open NOR flash manager */
/* lx_nor_flash_sector_read Read a NOR sector */
/* lx_nor_flash_sector_release Release a NOR sector */
/* lx_nor_flash_sector_write Write a NOR sector */
/* */
/* CALLED BY */
/* */
/* FileX System Functions */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
VOID _fx_nor_flash_simulator_driver(FX_MEDIA *media_ptr)
{
UCHAR *source_buffer;
UCHAR *destination_buffer;
ULONG logical_sector;
ULONG i;
UINT status;
/* There are several useful/important pieces of information contained in the media
structure, some of which are supplied by FileX and others are for the driver to
setup. The following is a summary of the necessary FX_MEDIA structure members:
FX_MEDIA Member Meaning
fx_media_driver_request FileX request type. Valid requests from FileX are
as follows:
FX_DRIVER_READ
FX_DRIVER_WRITE
FX_DRIVER_FLUSH
FX_DRIVER_ABORT
FX_DRIVER_INIT
FX_DRIVER_BOOT_READ
FX_DRIVER_RELEASE_SECTORS
FX_DRIVER_BOOT_WRITE
FX_DRIVER_UNINIT
fx_media_driver_status This value is RETURNED by the driver. If the
operation is successful, this field should be
set to FX_SUCCESS for before returning. Otherwise,
if an error occurred, this field should be set
to FX_IO_ERROR.
fx_media_driver_buffer Pointer to buffer to read or write sector data.
This is supplied by FileX.
fx_media_driver_logical_sector Logical sector FileX is requesting.
fx_media_driver_sectors Number of sectors FileX is requesting.
The following is a summary of the optional FX_MEDIA structure members:
FX_MEDIA Member Meaning
fx_media_driver_info Pointer to any additional information or memory.
This is optional for the driver use and is setup
from the fx_media_open call. The RAM disk uses
this pointer for the RAM disk memory itself.
fx_media_driver_write_protect The DRIVER sets this to FX_TRUE when media is write
protected. This is typically done in initialization,
but can be done anytime.
fx_media_driver_free_sector_update The DRIVER sets this to FX_TRUE when it needs to
know when clusters are released. This is important
for FLASH wear-leveling drivers.
fx_media_driver_system_write FileX sets this flag to FX_TRUE if the sector being
written is a system sector, e.g., a boot, FAT, or
directory sector. The driver may choose to use this
to initiate error recovery logic for greater fault
tolerance.
fx_media_driver_data_sector_read FileX sets this flag to FX_TRUE if the sector(s) being
read are file data sectors, i.e., NOT system sectors.
fx_media_driver_sector_type FileX sets this variable to the specific type of
sector being read or written. The following sector
types are identified:
FX_UNKNOWN_SECTOR
FX_BOOT_SECTOR
FX_FAT_SECTOR
FX_DIRECTORY_SECTOR
FX_DATA_SECTOR
*/
/* Process the driver request specified in the media control block. */
switch(media_ptr -> fx_media_driver_request)
{
case FX_DRIVER_READ:
{
/* Setup the destination buffer and logical sector. */
logical_sector = media_ptr -> fx_media_driver_logical_sector;
destination_buffer = (UCHAR *) media_ptr -> fx_media_driver_buffer;
/* Loop to read sectors from flash. */
for (i = 0; i < media_ptr -> fx_media_driver_sectors; i++)
{
/* Read a sector from NOR flash. */
status = lx_nor_flash_sector_read(&nor_flash, logical_sector, destination_buffer);
/* Determine if the read was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Move to the next entries. */
logical_sector++;
destination_buffer = destination_buffer + 512;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_WRITE:
{
/* Setup the source buffer and logical sector. */
logical_sector = media_ptr -> fx_media_driver_logical_sector;
source_buffer = (UCHAR *) media_ptr -> fx_media_driver_buffer;
/* Loop to write sectors to flash. */
for (i = 0; i < media_ptr -> fx_media_driver_sectors; i++)
{
/* Write a sector to NOR flash. */
status = lx_nor_flash_sector_write(&nor_flash, logical_sector, source_buffer);
/* Determine if the write was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Move to the next entries. */
logical_sector++;
source_buffer = source_buffer + 512;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_RELEASE_SECTORS:
{
/* Setup the logical sector. */
logical_sector = media_ptr -> fx_media_driver_logical_sector;
/* Release sectors. */
for (i = 0; i < media_ptr -> fx_media_driver_sectors; i++)
{
/* Release NOR flash sector. */
status = lx_nor_flash_sector_release(&nor_flash, logical_sector);
/* Determine if the sector release was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Move to the next entries. */
logical_sector++;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_FLUSH:
{
/* Return driver success. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_ABORT:
{
/* Return driver success. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_INIT:
{
/* FLASH drivers are responsible for setting several fields in the
media structure, as follows:
media_ptr -> fx_media_driver_free_sector_update
media_ptr -> fx_media_driver_write_protect
The fx_media_driver_free_sector_update flag is used to instruct
FileX to inform the driver whenever sectors are not being used.
This is especially useful for FLASH managers so they don't have
maintain mapping for sectors no longer in use.
The fx_media_driver_write_protect flag can be set anytime by the
driver to indicate the media is not writable. Write attempts made
when this flag is set are returned as errors. */
/* Perform basic initialization here... since the boot record is going
to be read subsequently and again for volume name requests. */
/* With flash wear leveling, FileX should tell wear leveling when sectors
are no longer in use. */
media_ptr -> fx_media_driver_free_sector_update = FX_TRUE;
/* Open the NOR flash simulation. */
status = lx_nor_flash_open(&nor_flash, "sim nor flash", _lx_nor_flash_simulator_initialize);
/* Determine if the flash open was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_UNINIT:
{
/* There is nothing to do in this case for the RAM driver. For actual
devices some shutdown processing may be necessary. */
/* Close the NOR flash simulation. */
status = lx_nor_flash_close(&nor_flash);
/* Determine if the flash close was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_READ:
{
/* Read the boot record and return to the caller. */
/* Setup the destination buffer. */
destination_buffer = (UCHAR *) media_ptr -> fx_media_driver_buffer;
/* Read boot sector from NOR flash. */
status = lx_nor_flash_sector_read(&nor_flash, 0, destination_buffer);
/* For NOR driver, determine if the boot record is valid. */
if ((destination_buffer[0] != (UCHAR) 0xEB) ||
(destination_buffer[1] != (UCHAR) 0x34) ||
(destination_buffer[2] != (UCHAR) 0x90))
{
/* Invalid boot record, return an error! */
media_ptr -> fx_media_driver_status = FX_MEDIA_INVALID;
return;
}
/* Determine if the boot read was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break;
}
case FX_DRIVER_BOOT_WRITE:
{
/* Write the boot record and return to the caller. */
/* Setup the source buffer. */
source_buffer = (UCHAR *) media_ptr -> fx_media_driver_buffer;
/* Write boot sector to NOR flash. */
status = lx_nor_flash_sector_write(&nor_flash, 0, source_buffer);
/* Determine if the boot write was successful. */
if (status != LX_SUCCESS)
{
/* Return an I/O error to FileX. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
return;
}
/* Successful driver request. */
media_ptr -> fx_media_driver_status = FX_SUCCESS;
break ;
}
default:
{
/* Invalid driver request. */
media_ptr -> fx_media_driver_status = FX_IO_ERROR;
break;
}
}
}
@@ -0,0 +1,182 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_256byte_ecc_check PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks 256 bytes of a NAND flash and ECC and */
/* attempts to correct any single bit errors. */
/* */
/* INPUT */
/* */
/* page_buffer Page buffer */
/* ecc_buffer Returned ECC buffer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_256byte_ecc_compute Compute ECC for 256 bytes */
/* */
/* CALLED BY */
/* */
/* _lx_nand_flash_page_ecc_check NAND page check */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_256byte_ecc_check(UCHAR *page_buffer, UCHAR *ecc_buffer)
{
INT i, j;
UCHAR mask;
UCHAR new_ecc_buffer[3];
UCHAR ecc_errors[3];
INT error_count;
USHORT *data;
USHORT byte;
USHORT bit;
ULONG correction_code;
/* Clear the error count. */
ecc_errors[0] = 0;
ecc_errors[1] = 0;
ecc_errors[2] = 0;
/* Calculate a new ECC for the 256 byte buffer. */
_lx_nand_flash_256byte_ecc_compute(page_buffer, new_ecc_buffer);
/* Clear error count. */
error_count = 0;
/* Loop through the ECC bytes to determine if there is an error in the page. */
for (i = 0; i < 3; i++)
{
/* Check for differences in the ECCs. */
ecc_errors[i] = new_ecc_buffer[i] ^ ecc_buffer[i];
/* Are there any errors? */
if (ecc_errors[i])
{
/* Accumulate the count of set bits. */
mask = 1;
for (j = 0; j < 8; j++)
{
/* Is this bit set? */
if (ecc_errors[i] & mask)
{
/* Yes, increment the count. */
error_count++;
}
/* Move mask to next bit. */
mask = (UCHAR) ((mask << 1) & 0xFF);
}
}
}
/* Determine if there are any errors. */
if (error_count == 0)
{
/* Everything is okay, return success. */
return(LX_SUCCESS);
}
/* Was a correctable error discovered? */
else if (error_count == 11)
{
/* Initialize bit and byte offset values. */
bit = 0;
byte = 0;
/* Setup the data pointer. */
data = (USHORT *) page_buffer;
/* Calculate the 32-bit correction code. */
correction_code = (ULONG) (ecc_errors[2] << 16) | (ULONG)(ecc_errors[1] << 8) | (ULONG)ecc_errors[0];
/* Unpack the correction code. */
byte = (USHORT) ((byte | ((correction_code >> (21+2)) & 1) << 6) & 0xFFFF);
byte = (USHORT) ((byte | ((correction_code >> (19+2)) & 1) << 5) & 0xFFFF);
byte = (USHORT) ((byte | ((correction_code >> (17+2)) & 1) << 4) & 0xFFFF);
byte = (USHORT) ((byte | ((correction_code >> (15+2)) & 1) << 3) & 0xFFFF);
byte = (USHORT) ((byte | ((correction_code >> (13+2)) & 1) << 2) & 0xFFFF);
byte = (USHORT) ((byte | ((correction_code >> (11+2)) & 1) << 1) & 0xFFFF);
byte = (USHORT) ((byte | ((correction_code >> (9+2)) & 1) << 0) & 0xFFFF);
bit = (USHORT) ((bit | ((correction_code >> (7+2)) & 1) << 3) & 0xFFFF);
bit = (USHORT) ((bit | ((correction_code >> (5+2)) & 1) << 2) & 0xFFFF);
bit = (USHORT) ((bit | ((correction_code >> (3+2)) & 1) << 1) & 0xFFFF);
bit = (USHORT) ((bit | ((correction_code >> (1+2)) & 1) << 0) & 0xFFFF);
/* Fix the error. */
data[byte] = (USHORT) ((data[byte] ^ (1 << bit)) & 0xFFFF);
/* Return an error corrected status. */
return(LX_NAND_ERROR_CORRECTED);
}
/* Otherwise, an unrecoverable ECC or data error is present. */
else
{
/* Return an error. */
return(LX_NAND_ERROR_NOT_CORRECTED);
}
}
@@ -0,0 +1,229 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_256byte_ecc_compute PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function computes the ECC for 256 bytes of a NAND flash page. */
/* The resulting ECC code is returned in 3 bytes. */
/* */
/* INPUT */
/* */
/* page_buffer Page buffer */
/* ecc_buffer Returned ECC buffer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _lx_nand_flash_page_ecc_compute NAND page ECC compute */
/* _lx_nand_flash_256byte_ecc_check Check 256 bytes and ECC */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_256byte_ecc_compute(UCHAR *page_buffer, UCHAR *ecc_buffer)
{
USHORT i, j;
USHORT *data;
USHORT bits, mask;
USHORT bit_parity;
USHORT even_bit_parity;
USHORT odd_bit_parity;
USHORT even_byte_parity;
USHORT odd_byte_parity;
/* Initialize local variables. */
bit_parity = 0;
even_bit_parity = 0;
odd_bit_parity = 0;
even_byte_parity = 0;
odd_byte_parity = 0;
/* Initialize the return ECC code area. */
ecc_buffer[0]= 0;
ecc_buffer[1]= 0;
ecc_buffer[2]= 0;
/* Setup a 16-bit pointer to the buffer area. */
data = (USHORT *) page_buffer;
/* Loop through the 256 byte buffer, 16 bits at a time. */
for (i = 0; i < 128; i++)
{
/* Compute the ECC value. */
bit_parity = bit_parity ^ data[i];
/* Now count the bits in the current data word. */
bits = 0;
mask = 1;
for (j = 0; j < 16; j++)
{
/* Is the bit set? */
if (data[i] & mask)
{
/* Yes, increment the bit count. */
bits++;
}
/* Move the mask to the next bit. */
mask = (USHORT) ((mask << 1) & 0xFFFF);
}
/* Determine if the number of bits is odd. */
if ((bits & 1) == 1)
{
/* Odd number of bits. Adjust the odd/even byte parity. */
even_byte_parity = (USHORT) ((even_byte_parity ^ (0xffff - i)) & 0xFFFF);
odd_byte_parity = odd_byte_parity ^ i;
}
}
/* Now look for bits set in the bit parity. */
for (i = 0; i < 16; i++)
{
/* Is the bit set? */
if (bit_parity & 1)
{
/* Yes, adjust the odd even byte parity. */
even_bit_parity = (USHORT) ((even_bit_parity ^ (15 - i)) & 0xFFFF);
odd_bit_parity = odd_bit_parity ^ i;
}
/* Look at next bit position. */
bit_parity = bit_parity >> 1;
}
/* At this point, we need to pack the 22 ECC bits into the 3 byte return area. */
/* Pack bit 21. */
ecc_buffer[(21+2)/8] = ((UCHAR)(ecc_buffer[(21+2)/8] | ((odd_byte_parity >> 6) & 1) << (21+2)%8) & 0xFF);
/* Pack bit 20. */
ecc_buffer[(20+2)/8] = ((UCHAR)(ecc_buffer[(20+2)/8] | ((even_byte_parity >> 6) & 1) << (20+2)%8) & 0xFF);
/* Pack bit 19. */
ecc_buffer[(19+2)/8] = ((UCHAR)(ecc_buffer[(19+2)/8] | ((odd_byte_parity >> 5) & 1) << (19+2)%8) & 0xFF);
/* Pack bit 18. */
ecc_buffer[(18+2)/8] = ((UCHAR)(ecc_buffer[(18+2)/8] | ((even_byte_parity >> 5) & 1) << (18+2)%8) & 0xFF);
/* Pack bit 17. */
ecc_buffer[(17+2)/8] = ((UCHAR)(ecc_buffer[(17+2)/8] | ((odd_byte_parity >> 4) & 1) << (17+2)%8) & 0xFF);
/* Pack bit 16. */
ecc_buffer[(16+2)/8] = ((UCHAR)(ecc_buffer[(16+2)/8] | ((even_byte_parity >> 4) & 1) << (16+2)%8) & 0xFF);
/* Pack bit 15. */
ecc_buffer[(15+2)/8] = ((UCHAR)(ecc_buffer[(15+2)/8] | ((odd_byte_parity >> 3) & 1) << (15+2)%8) & 0xFF);
/* Pack bit 14. */
ecc_buffer[(14+2)/8] = ((UCHAR)(ecc_buffer[(14+2)/8] | ((even_byte_parity >> 3) & 1) << (14+2)%8) & 0xFF);
/* Pack bit 13. */
ecc_buffer[(13+2)/8] = ((UCHAR)(ecc_buffer[(13+2)/8] | ((odd_byte_parity >> 2) & 1) << (13+2)%8) & 0xFF);
/* Pack bit 12. */
ecc_buffer[(12+2)/8] = ((UCHAR)(ecc_buffer[(12+2)/8] | ((even_byte_parity >> 2) & 1) << (12+2)%8) & 0xFF);
/* Pack bit 11. */
ecc_buffer[(11+2)/8] = ((UCHAR)(ecc_buffer[(11+2)/8] | ((odd_byte_parity >> 1) & 1) << (11+2)%8) & 0xFF);
/* Pack bit 10. */
ecc_buffer[(10+2)/8] = ((UCHAR)(ecc_buffer[(10+2)/8] | ((even_byte_parity >> 1) & 1) << (10+2)%8) & 0xFF);
/* Pack bit 9. */
ecc_buffer[(9+2)/8] = ((UCHAR)(ecc_buffer[(9+2)/8] | ((odd_byte_parity >> 0) & 1) << (9+2)%8) & 0xFF);
/* Pack bit 8. */
ecc_buffer[(8+2)/8] = ((UCHAR)(ecc_buffer[(8+2)/8] | ((even_byte_parity >> 0) & 1) << (8+2)%8) & 0xFF);
/* Pack bit 7. */
ecc_buffer[(7+2)/8] = ((UCHAR)(ecc_buffer[(7+2)/8] | ((odd_bit_parity >> 3) & 1) << (7+2)%8) & 0xFF);
/* Pack bit 6. */
ecc_buffer[(6+2)/8] = ((UCHAR)(ecc_buffer[(6+2)/8] | ((even_bit_parity >> 3) & 1) << (6+2)%8) & 0xFF);
/* Pack bit 5. */
ecc_buffer[(5+2)/8] = ((UCHAR)(ecc_buffer[(5+2)/8] | ((odd_bit_parity >> 2) & 1) << (5+2)%8) & 0xFF);
/* Pack bit 4. */
ecc_buffer[(4+2)/8] = ((UCHAR)(ecc_buffer[(4+2)/8] | ((even_bit_parity >> 2) & 1) << (4+2)%8) & 0xFF);
/* Pack bit 3. */
ecc_buffer[(3+2)/8] = ((UCHAR)(ecc_buffer[(3+2)/8] | ((odd_bit_parity >> 1) & 1) << (3+2)%8) & 0xFF);
/* Pack bit 2. */
ecc_buffer[(2+2)/8] = ((UCHAR)(ecc_buffer[(2+2)/8] | ((even_bit_parity >> 1) & 1) << (2+2)%8) & 0xFF);
/* Pack bit 1. */
ecc_buffer[(1+2)/8] = ((UCHAR)(ecc_buffer[(1+2)/8] | ((odd_bit_parity >> 0) & 1) << (1+2)%8) & 0xFF);
/* Pack bit 0. */
ecc_buffer[(0+2)/8] = ((UCHAR)(ecc_buffer[(0+2)/8] | ((even_bit_parity >> 0) & 1) << (0+2)%8) & 0xFF);
/* Return success! */
return(LX_SUCCESS);
}
@@ -0,0 +1,180 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_block_full_update PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function writes the list of page to logical sector mapping */
/* when the block is full. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block that is full */
/* erase_count Block erase count */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_driver_write Driver flash page write */
/* _lx_nand_flash_driver_extra_bytes_get Get extra bytes from spare */
/* _lx_nand_flash_driver_extra_bytes_set Set extra bytes from spare */
/* _lx_nand_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_block_full_update(LX_NAND_FLASH *nand_flash, ULONG block, ULONG erase_count)
{
LX_NAND_PAGE_EXTRA_INFO extra_info;
UINT status;
ULONG i;
ULONG *list_ptr;
/* Setup pointer to internal buffer. */
list_ptr = nand_flash -> lx_nand_flash_page_buffer;
/* Set the internal buffer of all ones. */
for (i = 0; i < nand_flash -> lx_nand_flash_words_per_page; i++)
{
/* Set the buffer to all ones. */
list_ptr[i] = LX_ALL_ONES;
}
/* Set the initial word to the erase count (this is what is already there!). */
list_ptr[0] = erase_count;
/* Now walk through the pages in the block to build the list of mapped logical
sectors to pages. */
i = 1;
while (i < nand_flash -> lx_nand_flash_pages_per_block)
{
/* Read the extra bytes of each page to pickup the associated mapping. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, block, i, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, i);
/* Return the error... no point in continuing. */
return(status);
}
/* Determine if the extra info indicates the page has not yet been allocated. */
if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE)
{
/* Block not full, get out of the loop. */
break;
}
/* Save the mapping. */
list_ptr[i] = extra_info.lx_nand_page_extra_info_logical_sector;
/* Move to next entry. */
i++;
}
/* Check for a full block. */
if (i == nand_flash -> lx_nand_flash_pages_per_block)
{
/* Yes, the block is full. */
/* Place the list complete marker so we know the list is intact. */
list_ptr[i] = LX_NAND_PAGE_LIST_VALID;
/* At this point we can write the buffer to page 0 of the block. */
/* Write the mapping list to page 0. */
status = _lx_nand_flash_driver_write(nand_flash, block, 0, list_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return the error... no point in continuing. */
return(status);
}
/* Write the extra bytes for page 0. */
extra_info.lx_nand_page_extra_info_logical_sector = ((ULONG) LX_NAND_PAGE_FREE) & ~(((ULONG) LX_NAND_BLOCK_EMPTY) | ((ULONG) LX_NAND_BLOCK_FULL));
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, block, 0, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
}
}
/* Return status. */
return(status);
}
@@ -0,0 +1,369 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_block_obsoleted_check PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks to see if the specified block is completely */
/* obsoleted. If so, the block is reclaimed (erased) and made */
/* available. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block number to check */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_driver_block_status_get */
/* Driver block status */
/* _lx_nand_flash_driver_block_erase Driver block erase */
/* _lx_nand_flash_driver_extra_bytes_get Driver get extra bytes */
/* _lx_nand_flash_driver_block_status_set */
/* Driver set extra bytes */
/* _lx_nand_flash_driver_read Driver page read */
/* _lx_nand_flash_driver_write Driver page write */
/* _lx_nand_flash_block_reclaim Reclaim one block */
/* _lx_nand_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
VOID _lx_nand_flash_block_obsoleted_check(LX_NAND_FLASH *nand_flash, ULONG block)
{
LX_NAND_PAGE_EXTRA_INFO extra_info;
UCHAR block_status;
ULONG *page_word_ptr;
ULONG erase_count;
ULONG j;
UINT status;
/* First, check to make sure this block is good. */
status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Simply return. */
return;
}
/* Is this block bad? */
if (block_status != LX_NAND_GOOD_BLOCK)
{
/* Yes, this block is bad. */
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Simply return. */
return;
}
/* Read the extra bytes of page 0. This will tell us if the page has any valid mappings. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, block, 0, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Simply return. */
return;
}
/* Determine if the block is full, since it must be full first before it can be
completely obsoleted. */
if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_BLOCK_FULL) != 0)
{
/* This block is not full, therefore it cannot be obsoleted. */
/* Simply return. */
return;
}
/* Setup pointer to internal buffer. */
page_word_ptr = nand_flash -> lx_nand_flash_page_buffer;
/* Now read page 0 of the block, which has the erase count in the first 4 bytes. */
status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
/* Simply return. */
return;
}
}
/* Determine if we have a valid logical sector mapping list. */
if ((page_word_ptr[1] != LX_NAND_PAGE_FREE) &&
(page_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] == LX_NAND_PAGE_LIST_VALID))
{
/* Yes, we have a valid logical sector mapping list in page 0. */
/* Traverse the list to look for the logical sector. */
for (j = 1; j < nand_flash -> lx_nand_flash_pages_per_block; j++)
{
/* Is this entry valid? */
if (page_word_ptr[j] & LX_NAND_PAGE_VALID)
{
/* Read in the actual page entry to make sure this logical sector mapping is still valid. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, block, j, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, j);
/* Simply return. */
return;
}
/* Determine if the actual page is still valid. */
if (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_VALID)
{
/* If so, we found a valid page so the block isn't completely obsoleted. */
/* Simply return. */
return;
}
}
}
/* Pickup the erase count. */
erase_count = page_word_ptr[0];
/* Determine if we need to reclaim blocks to balance out the erase counts. */
if ((erase_count == nand_flash -> lx_nand_flash_maximum_erase_count) &&
((nand_flash -> lx_nand_flash_maximum_erase_count - nand_flash -> lx_nand_flash_minimum_erase_count) >= LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA))
{
/* Attempt to reclaim one block. */
_lx_nand_flash_block_reclaim(nand_flash);
}
else
{
/* At this point we can reclaim the block. */
/* Write the erased started indication. */
page_word_ptr[0] = LX_BLOCK_ERASE_STARTED;
status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
}
/* Erase the entire block. */
status = _lx_nand_flash_driver_block_erase(nand_flash, block, erase_count+1);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Attempt to mark this block as bad. */
status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK);
/* Check for error in setting the block status. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
}
/* Increment the bad block count. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Update number of obsolete pages but not free pages since this block is now bad. */
nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - (nand_flash -> lx_nand_flash_pages_per_block - 1);
}
else
{
/* Increment the erase count. */
erase_count++;
/* Determine if the new erase count exceeds the maximum. */
if (erase_count > ((ULONG) LX_BLOCK_ERASE_COUNT_MAX))
{
/* Yes, erase count is in overflow. Stay at the maximum count. */
erase_count = ((ULONG) LX_BLOCK_ERASE_COUNT_MAX);
}
/* Determine if we need to update the maximum erase count. */
if (erase_count > nand_flash -> lx_nand_flash_maximum_erase_count)
{
/* Yes, a new maximum is present. */
nand_flash -> lx_nand_flash_maximum_erase_count = erase_count;
/* Determine if the search pointer is on this block. */
if (nand_flash -> lx_nand_flash_free_block_search == block)
{
/* Move to next block. */
nand_flash -> lx_nand_flash_free_block_search++;
/* Check for wrap condition. */
if (nand_flash -> lx_nand_flash_free_block_search >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Reset to the beginning block. */
nand_flash -> lx_nand_flash_free_block_search = 0;
}
}
}
/* Set the buffer to all ones. */
for (j = 0; j < nand_flash -> lx_nand_flash_words_per_page; j++)
{
/* Set word to all ones. */
page_word_ptr[j] = LX_ALL_ONES;
}
/* Now store the erase count. */
page_word_ptr[0] = (erase_count | LX_BLOCK_ERASED);
/* Write the erase count for the block. */
status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
/* Check to see if the write was successful. */
if (status == LX_SUCCESS)
{
/* Now store the erase count. */
page_word_ptr[0] = erase_count;
/* Write the erase count for the block. */
status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
}
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Attempt to mark this block as bad. */
status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK);
/* Check for error in setting the block status. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Simply return. */
return;
}
/* Increment the bad block count. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Update number of obsolete pages but not free pages since this block is now bad. */
nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - (nand_flash -> lx_nand_flash_pages_per_block - 1);
}
else
{
/* Update parameters of this flash. */
nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages + (nand_flash -> lx_nand_flash_pages_per_block - 1);
nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - (nand_flash -> lx_nand_flash_pages_per_block - 1);
}
}
}
}
}
+631
View File
@@ -0,0 +1,631 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_block_reclaim PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reclaims one block from the NAND flash. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_driver_block_erase Driver erase block */
/* _lx_nand_flash_driver_block_status_set */
/* Set block status to bad */
/* _lx_nand_flash_driver_extra_bytes_get NAND flash get extra bytes */
/* _lx_nand_flash_driver_extra_bytes_set NAND flash set extra bytes */
/* _lx_nand_flash_driver_write Driver flash page write */
/* _lx_nand_flash_driver_read Driver flash page read */
/* _lx_nand_flash_block_full_update Update page 0 with list of */
/* mapped pages */
/* _lx_nand_flash_next_block_to_erase_find */
/* Find next block to erase */
/* _lx_nand_flash_physical_page_allocate Allocate new page */
/* _lx_nand_flash_sector_mapping_cache_invalidate */
/* Invalidate cache entry */
/* _lx_nand_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_block_reclaim(LX_NAND_FLASH *nand_flash)
{
LX_NAND_PAGE_EXTRA_INFO old_extra_info;
LX_NAND_PAGE_EXTRA_INFO new_extra_info;
ULONG *page_word_ptr;
ULONG i;
ULONG erase_block;
ULONG erase_count;
ULONG mapped_pages;
ULONG obsolete_pages;
ULONG free_pages;
ULONG logical_sector;
ULONG new_block;
ULONG new_page;
ULONG new_erase_count;
UINT status;
/* Increment the reclaim attempts counter. */
nand_flash -> lx_nand_flash_diagnostic_block_reclaim_attempts++;
/* Determine the next block to erase. */
_lx_nand_flash_next_block_to_erase_find(nand_flash, &erase_block, &erase_count, &mapped_pages, &obsolete_pages);
/* Setup pointer to page memory. */
page_word_ptr = nand_flash -> lx_nand_flash_page_buffer;
/* Determine if the search pointer is set for this block. */
if (nand_flash -> lx_nand_flash_free_block_search == erase_block)
{
/* Ensure the search block is not the block we are trying to free. */
nand_flash -> lx_nand_flash_free_block_search = erase_block + 1;
/* Check for wrap condition. */
if (nand_flash -> lx_nand_flash_free_block_search >= nand_flash -> lx_nand_flash_total_blocks)
nand_flash -> lx_nand_flash_free_block_search = 0;
}
/* Determine if this block is completely obsolete. */
if (obsolete_pages == nand_flash -> lx_nand_flash_pages_per_block)
{
/* Read page 0 of the block, which has the erase count in the first 4 bytes. */
status = _lx_nand_flash_driver_read(nand_flash, erase_block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
}
/* Write the erased started indication. */
page_word_ptr[0] = LX_BLOCK_ERASE_STARTED;
status = _lx_nand_flash_driver_write(nand_flash, erase_block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
}
/* Erase the entire block. */
status = _lx_nand_flash_driver_block_erase(nand_flash, erase_block, erase_count+1);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
/* Attempt to mark this block as bad. */
status = _lx_nand_flash_driver_block_status_set(nand_flash, erase_block, LX_NAND_BAD_BLOCK);
/* Check for error in setting the block status. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
}
/* Increment the bad block count. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Update number of obsolete pages but not free pages since this block is now bad. */
nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages;
}
else
{
/* Increment the erase count. */
erase_count++;
/* Determine if the new erase count exceeds the maximum. */
if (erase_count > ((ULONG) LX_BLOCK_ERASE_COUNT_MAX))
{
/* Yes, erase count is in overflow. Stay at the maximum count. */
erase_count = ((ULONG) LX_BLOCK_ERASE_COUNT_MAX);
}
/* Determine if we need to update the maximum erase count. */
if (erase_count > nand_flash -> lx_nand_flash_maximum_erase_count)
{
/* Yes, a new maximum is present. */
nand_flash -> lx_nand_flash_maximum_erase_count = erase_count;
}
/* Set the buffer to all ones. */
for (i = 0; i < nand_flash -> lx_nand_flash_words_per_page; i++)
{
/* Set word to all ones. */
page_word_ptr[i] = LX_ALL_ONES;
}
/* Now store the erase count. */
page_word_ptr[0] = (erase_count | LX_BLOCK_ERASED);
/* Write the erase count for the block. */
status = _lx_nand_flash_driver_write(nand_flash, erase_block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
/* Check the status. */
if (status == LX_SUCCESS)
{
/* Now store the erase count. */
page_word_ptr[0] = erase_count;
/* Write the erase count for the block. */
status = _lx_nand_flash_driver_write(nand_flash, erase_block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
}
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
/* Attempt to mark this block as bad. */
status = _lx_nand_flash_driver_block_status_set(nand_flash, erase_block, LX_NAND_BAD_BLOCK);
/* Check for error in setting the block status. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
}
/* Increment the bad block count. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Update number of obsolete pages but not free pages since this block is now bad. */
nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages;
}
else
{
/* Update parameters of this flash. */
nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages + obsolete_pages;
nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages;
}
}
}
else
{
/* Calculate the number of free pages in this block. */
free_pages = nand_flash -> lx_nand_flash_pages_per_block - (obsolete_pages + mapped_pages);
/* Determine if there are enough free pages outside of this block to reclaim this block. */
if (mapped_pages <= (nand_flash -> lx_nand_flash_free_pages - free_pages))
{
/* Now search through the list to find mapped logical sectors to move. */
for (i = 1; i < nand_flash -> lx_nand_flash_pages_per_block; i++)
{
/* Read the logical sector mapping for this page. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, erase_block, i, (UCHAR *) &old_extra_info, sizeof(old_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, i);
/* Return the error. */
return(status);
}
/* Determine if the entry hasn't been used. */
if (old_extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE)
{
/* Since allocations are done sequentially in the block, we know nothing
else exists after this point. */
break;
}
/* Is this entry mapped? */
if (old_extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_VALID)
{
/* Pickup the logical sector associated with this mapped page. */
logical_sector = old_extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK;
/* Invalidate the old logical sector mapping cache entry. */
_lx_nand_flash_sector_mapping_cache_invalidate(nand_flash, logical_sector);
/* Allocate a new page for this write. */
_lx_nand_flash_physical_page_allocate(nand_flash, &new_block, &new_page, &new_erase_count);
/* Check to see if the new block is the same as the block we are trying to reclaim. */
if (new_block == erase_block)
{
/* Yes, the new page was found in the block to be erased. Simply move the search pointer
to the block after the erase block and search for another page from there. */
nand_flash -> lx_nand_flash_free_block_search = erase_block + 1;
/* Check for wrap condition. */
if (nand_flash -> lx_nand_flash_free_block_search >= nand_flash -> lx_nand_flash_total_blocks)
nand_flash -> lx_nand_flash_free_block_search = 0;
/* Allocate new page again. */
_lx_nand_flash_physical_page_allocate(nand_flash, &new_block, &new_page, &new_erase_count);
/* Check again for the new page inside of the block to erase. This should be impossible, since
we check previously if there are enough free pages outside of this block needed to reclaim
this block. */
if (new_block == erase_block)
{
/* System error, a new page is not available outside of the erase block.
Clear the new page so we fall through to the error handling. */
new_page = 0;
}
}
/* Determine if the new page allocation was successful. */
if (new_page)
{
/* Yes, we were able to allocate a new page for the logical sector. */
/* Read the existing page into the internal buffer. */
status = _lx_nand_flash_driver_read(nand_flash, erase_block, i, page_word_ptr, nand_flash -> lx_nand_flash_words_per_page);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, i);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
/* Return the error. */
return(status);
}
}
/* Write the logical sector data to the new page. */
status = _lx_nand_flash_driver_write(nand_flash, new_block, new_page, page_word_ptr, nand_flash -> lx_nand_flash_words_per_page);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, new_block, new_page);
/* Return the error. */
return(status);
}
/* Now deprecate the old logical sector mapping. */
/* Clear bit 30, which indicates this page is being superceded. */
old_extra_info.lx_nand_page_extra_info_logical_sector = old_extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_SUPERCEDED);
/* Write the value back to the flash to clear bit 30. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, erase_block, i, (UCHAR *) &old_extra_info, sizeof(old_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, i);
/* Return the error. */
return(status);
}
/* Now build the new mapping entry - with the not valid bit set initially. */
new_extra_info.lx_nand_page_extra_info_logical_sector = ((ULONG) LX_NAND_PAGE_VALID) | ((ULONG) LX_NAND_PAGE_SUPERCEDED) | ((ULONG) LX_NAND_PAGE_MAPPING_NOT_VALID) | logical_sector;
/* Write out the new mapping entry. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, new_block, new_page, (UCHAR *) &new_extra_info, sizeof(new_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, new_block, new_page);
/* Return the error. */
return(status);
}
/* Now clear the not valid bit to make this sector mapping valid. This is done because the writing of the extra bytes itself can
be interrupted and we need to make sure this can be detected when the flash is opened again. */
new_extra_info.lx_nand_page_extra_info_logical_sector = new_extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_MAPPING_NOT_VALID);
/* Clear the not valid bit. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, new_block, new_page, (UCHAR *) &new_extra_info, sizeof(new_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, new_block, new_page);
/* Return the error. */
return(status);
}
#ifdef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
/* Determine if this logical sector fits in the logical sector direct cache mapping. */
if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE)
{
/* Remember the mapping for this logical sector. */
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) new_block;
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) new_page;
}
#endif
/* Now clear bit 31, which indicates this sector is now obsoleted. */
old_extra_info.lx_nand_page_extra_info_logical_sector = old_extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_VALID);
/* Write the value back to the flash to clear bit 31. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, erase_block, i, (UCHAR *) &old_extra_info, sizeof(old_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, i);
/* Return the error. */
return(status);
}
/* Increment the number of moved pages. */
nand_flash -> lx_nand_flash_diagnostic_moved_pages++;
/* Determine if the new page is the last page of the block. */
if (new_page == (nand_flash -> lx_nand_flash_pages_per_block - 1))
{
/* Yes, we need to update page 0 of the block with the list of mapped
pages for this block. */
_lx_nand_flash_block_full_update(nand_flash, new_block, new_erase_count);
}
}
else
{
/* Call system error handler - the allocation should always succeed at this point. */
_lx_nand_flash_system_error(nand_flash, LX_SYSTEM_ALLOCATION_FAILED, erase_block, i);
/* System error... break! */
break;
}
/* Decrement the number of mapped pages. */
mapped_pages--;
/* Determine if we are done. */
if (mapped_pages == 0)
break;
}
}
/* Read page 0 of the block, which has the erase count in the first 4 bytes. */
status = _lx_nand_flash_driver_read(nand_flash, erase_block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
}
/* Write the erased started indication. */
page_word_ptr[0] = LX_BLOCK_ERASE_STARTED;
status = _lx_nand_flash_driver_write(nand_flash, erase_block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
}
/* Erase the entire block. */
status = _lx_nand_flash_driver_block_erase(nand_flash, erase_block, erase_count+1);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
/* Attempt to mark this block as bad. */
status = _lx_nand_flash_driver_block_status_set(nand_flash, erase_block, LX_NAND_BAD_BLOCK);
/* Check for error in setting the block status. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
}
/* Increment the bad block count. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Update number of obsolete pages but not free pages since this block is now bad. */
nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages;
}
else
{
/* Increment the erase count. */
erase_count++;
/* Determine if the new erase count exceeds the maximum. */
if (erase_count > ((ULONG) LX_BLOCK_ERASE_COUNT_MAX))
{
/* Yes, erase count is in overflow. Stay at the maximum count. */
erase_count = ((ULONG) LX_BLOCK_ERASE_COUNT_MAX);
}
/* Determine if we need to update the maximum erase count. */
if (erase_count > nand_flash -> lx_nand_flash_maximum_erase_count)
{
/* Yes, a new maximum is present. */
nand_flash -> lx_nand_flash_maximum_erase_count = erase_count;
}
/* Set the buffer to all ones. */
for (i = 0; i < nand_flash -> lx_nand_flash_words_per_page; i++)
{
/* Set word to all ones. */
page_word_ptr[i] = LX_ALL_ONES;
}
/* Now store the erase count. */
page_word_ptr[0] = (erase_count | LX_BLOCK_ERASED);
/* Write the erase count for the block. */
status = _lx_nand_flash_driver_write(nand_flash, erase_block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
/* Determine if the write was successful. */
if (status == LX_SUCCESS)
{
/* Now store the erase count. */
page_word_ptr[0] = erase_count;
/* Write the erase count for the block. */
status = _lx_nand_flash_driver_write(nand_flash, erase_block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
}
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
/* Attempt to mark this block as bad. */
status = _lx_nand_flash_driver_block_status_set(nand_flash, erase_block, LX_NAND_BAD_BLOCK);
/* Check for error in setting the block status. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, erase_block, 0);
/* Return the error. */
return(status);
}
/* Increment the bad block count. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Update number of obsolete pages but not free pages since this block is now bad. */
nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages;
}
else
{
/* Update parameters of this flash. */
nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages + obsolete_pages;
nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages - obsolete_pages;
}
}
}
}
/* Return status. */
return(LX_SUCCESS);
}
+129
View File
@@ -0,0 +1,129 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_close PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function closes a NAND flash instance. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* tx_mutex_delete Delete thread-safe mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_close(LX_NAND_FLASH *nand_flash)
{
TX_INTERRUPT_SAVE_AREA
/* Lockout interrupts for NAND flash close. */
TX_DISABLE
/* See if the media is the only one on the media opened list. */
if ((_lx_nand_flash_opened_ptr == nand_flash) &&
(_lx_nand_flash_opened_ptr == nand_flash -> lx_nand_flash_open_next) &&
(_lx_nand_flash_opened_ptr == nand_flash -> lx_nand_flash_open_previous))
{
/* Only opened NAND flash, just set the opened list to NULL. */
_lx_nand_flash_opened_ptr = LX_NULL;
}
else
{
/* Otherwise, not the only opened NAND flash, link-up the neighbors. */
(nand_flash -> lx_nand_flash_open_next) -> lx_nand_flash_open_previous =
nand_flash -> lx_nand_flash_open_previous;
(nand_flash -> lx_nand_flash_open_previous) -> lx_nand_flash_open_next =
nand_flash -> lx_nand_flash_open_next;
/* See if we have to update the opened list head pointer. */
if (_lx_nand_flash_opened_ptr == nand_flash)
{
/* Yes, move the head pointer to the next opened NAND flash. */
_lx_nand_flash_opened_ptr = nand_flash -> lx_nand_flash_open_next;
}
}
/* Decrement the opened NAND flash counter. */
_lx_nand_flash_opened_count--;
/* Finally, indicate that this NAND flash is closed. */
nand_flash -> lx_nand_flash_state = LX_NAND_FLASH_CLOSED;
/* Restore interrupt posture. */
TX_RESTORE
#ifdef LX_THREAD_SAFE_ENABLE
/* Delete the thread safe mutex. */
tx_mutex_delete(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return success. */
return(LX_SUCCESS);
}
+112
View File
@@ -0,0 +1,112 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_defragment PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function defragments the NAND flash. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_block_reclaim Reclaim a NAND flash block */
/* tx_mutex_get Get thread protection */
/* tx_mutex_put Release thread protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_defragment(LX_NAND_FLASH *nand_flash)
{
ULONG i;
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Loop for max number of blocks, while there are obsolete count. */
for (i = 0; i < nand_flash -> lx_nand_flash_total_blocks; i++)
{
/* Determine if there is any more defragment work. */
if (nand_flash -> lx_nand_flash_obsolete_pages == 0)
break;
/* Call the block reclaim function to defragment. */
_lx_nand_flash_block_reclaim(nand_flash);
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return successful completion. */
return(LX_SUCCESS);
}
@@ -0,0 +1,137 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_block_erase PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the driver to erase a block. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block number */
/* erase_count Erase count for this block */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* (lx_nand_flash_driver_block_erase) Driver erase block */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_block_erase(LX_NAND_FLASH *nand_flash, ULONG block, ULONG erase_count)
{
ULONG cache_index;
ULONG i;
UINT status;
/* Determine if the block status cache is enabled. */
if (nand_flash -> lx_nand_flash_block_status_cache != LX_NULL)
{
/* Save the block status value in the cache. */
nand_flash -> lx_nand_flash_block_status_cache[block] = 0xFF;
}
/* Determine if the page extra byte cache is enabled. */
if (nand_flash -> lx_nand_flash_page_extra_bytes_cache != LX_NULL)
{
/* Calculate the cache index. */
cache_index = (block * nand_flash -> lx_nand_flash_pages_per_block);
/* Loop to clear the entries in the page extra bytes cache. */
for (i = 0; i < nand_flash -> lx_nand_flash_pages_per_block; i++)
{
/* Clear each cache entry. */
nand_flash -> lx_nand_flash_page_extra_bytes_cache[cache_index+i].lx_nand_page_extra_info_logical_sector = (ULONG) 0xFFFFFFFF;
}
}
/* Determine if the page 0 cache is enabled. */
if (nand_flash -> lx_nand_flash_page_0_cache != LX_NULL)
{
/* Yes, the page 0 cache is enabled. */
/* Build index to page 0 cache. */
cache_index = block * (nand_flash -> lx_nand_flash_pages_per_block + 1);
/* Clear the associated page 0 cache. */
for (i = 0; i < (nand_flash -> lx_nand_flash_pages_per_block + 1); i++)
{
/* Clear each cache entry. */
nand_flash -> lx_nand_flash_page_0_cache[cache_index+i] = (ULONG) 0xFFFFFFFF;
}
}
/* Increment the block erases count. */
nand_flash -> lx_nand_flash_diagnostic_block_erases++;
/* Call driver erase block function. */
status = (nand_flash -> lx_nand_flash_driver_block_erase)(block, erase_count);
/* Return status. */
return(status);
}
@@ -0,0 +1,93 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_block_erased_verify PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the driver to verify the block was erased. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block number */
/* page Page number */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* (lx_nand_flash_driver_block_erased_verify) */
/* Driver verify page erased */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_block_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block)
{
UINT status;
/* Increment the block erased verify count. */
nand_flash -> lx_nand_flash_diagnostic_block_erased_verifies++;
/* Call driver block erased verify function. */
status = (nand_flash -> lx_nand_flash_driver_block_erased_verify)(block);
/* Return status. */
return(status);
}
@@ -0,0 +1,132 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_block_status_get PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the driver to get the block status and */
/* updates the internal cache. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block number */
/* bad_block_flag Pointer to Bad block flag */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* (lx_nand_flash_driver_block_status_get) */
/* NAND flash block status get */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_block_status_get(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR *bad_block_flag)
{
UINT status;
/* Determine if the block status cache is disabled. */
if (nand_flash -> lx_nand_flash_block_status_cache == LX_NULL)
{
/* Increment the block status get count. */
nand_flash -> lx_nand_flash_diagnostic_block_status_gets++;
/* Call driver block status get function. */
status = (nand_flash -> lx_nand_flash_driver_block_status_get)(block, bad_block_flag);
}
else
{
/* Determine if the block status cache entry is valid. */
if (nand_flash -> lx_nand_flash_block_status_cache[block] != 0)
{
/* Simply return this value. */
*bad_block_flag = nand_flash -> lx_nand_flash_block_status_cache[block];
/* Increment the number of status byte cache hits. */
nand_flash -> lx_nand_flash_diagnostic_block_status_cache_hits++;
/* Return successful status. */
status = LX_SUCCESS;
}
else
{
/* Increment the block status get count. */
nand_flash -> lx_nand_flash_diagnostic_block_status_gets++;
/* Call driver block status get function. */
status = (nand_flash -> lx_nand_flash_driver_block_status_get)(block, bad_block_flag);
/* Increment the number of status byte cache misses. */
nand_flash -> lx_nand_flash_diagnostic_block_status_cache_misses++;
/* Save the block status value in the cache. */
nand_flash -> lx_nand_flash_block_status_cache[block] = *bad_block_flag;
}
}
/* Return status. */
return(status);
}
@@ -0,0 +1,103 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_block_status_set PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the driver to set the block status and */
/* updates the internal cache. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block number */
/* bad_block_flag Bad block flag */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* (lx_nand_flash_driver_block_status_set) */
/* NAND flash block status set */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_block_status_set(LX_NAND_FLASH *nand_flash, ULONG block, UCHAR bad_block_flag)
{
UINT status;
/* Determine if the block status cache is enabled. */
if (nand_flash -> lx_nand_flash_block_status_cache != LX_NULL)
{
/* Save the block status value in the cache. */
nand_flash -> lx_nand_flash_block_status_cache[block] = bad_block_flag;
}
/* Increment the block status set count. */
nand_flash -> lx_nand_flash_diagnostic_block_status_sets++;
/* Call driver block status set function. */
status = (nand_flash -> lx_nand_flash_driver_block_status_set)(block, bad_block_flag);
/* Return status. */
return(status);
}
@@ -0,0 +1,148 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_extra_bytes_get PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the driver to get the extra bytes of a NAND */
/* page. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block number */
/* page Page number */
/* destination Pointer to destination buffer */
/* words Number of words to read */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* (lx_nand_flash_driver_extra_bytes_get)Get extra bytes from spare */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_extra_bytes_get(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *destination, UINT size)
{
ULONG *source_ptr;
ULONG *destination_ptr;
ULONG cache_index;
UINT status;
/* Determine if the page extra bytes cache is disabled. */
if (nand_flash -> lx_nand_flash_page_extra_bytes_cache == LX_NULL)
{
/* Increment the page extra bytes get count. */
nand_flash -> lx_nand_flash_diagnostic_page_extra_bytes_gets++;
/* Call driver extra bytes get function. */
status = (nand_flash -> lx_nand_flash_driver_extra_bytes_get)(block, page, destination, size);
}
else
{
/* Calculate the cache index. */
cache_index = (block * nand_flash -> lx_nand_flash_pages_per_block) + page;
/* Setup the destination pointer. */
destination_ptr = (ULONG *) destination;
/* Determine if this cache entry is valid. */
if (nand_flash -> lx_nand_flash_page_extra_bytes_cache[cache_index].lx_nand_page_extra_info_logical_sector != 0)
{
/* Simply return this value. */
*destination_ptr = nand_flash -> lx_nand_flash_page_extra_bytes_cache[cache_index].lx_nand_page_extra_info_logical_sector;
/* Increment the number of page extra bytes cache hits. */
nand_flash -> lx_nand_flash_diagnostic_page_extra_bytes_cache_hits++;
/* Return successful status. */
status = LX_SUCCESS;
}
else
{
/* Increment the page extra bytes get count. */
nand_flash -> lx_nand_flash_diagnostic_page_extra_bytes_gets++;
/* Call driver extra bytes get function. */
status = (nand_flash -> lx_nand_flash_driver_extra_bytes_get)(block, page, destination, size);
/* Increment the number of page extra bytes cache misses. */
nand_flash -> lx_nand_flash_diagnostic_page_extra_bytes_cache_misses++;
/* Setup destination pointer. */
destination_ptr = &nand_flash -> lx_nand_flash_page_extra_bytes_cache[cache_index].lx_nand_page_extra_info_logical_sector;
/* Setup source pointer. */
source_ptr = (ULONG *) destination;
/* Save the value in the page extra bytes cache. */
*destination_ptr = *source_ptr;
}
}
/* Return status. */
return(status);
}
@@ -0,0 +1,113 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_extra_bytes_set PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the driver extra bytes set operation and */
/* updates the internal cache. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block number */
/* page Page number */
/* source Pointer to source extra bytes */
/* size Number of extra bytes */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* (lx_nand_flash_driver_extra_bytes_set) */
/* NAND flash set extra bytes */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_extra_bytes_set(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, UCHAR *source, UINT size)
{
ULONG cache_index;
ULONG *destination_ptr;
UINT status;
/* Increment the page extra bytes set count. */
nand_flash -> lx_nand_flash_diagnostic_page_extra_bytes_sets++;
/* Call driver extra bytes set function. */
status = (nand_flash -> lx_nand_flash_driver_extra_bytes_set)(block, page, source, size);
/* Determine if the page extra bytes set cache is enabled. */
if (nand_flash -> lx_nand_flash_page_extra_bytes_cache != LX_NULL)
{
/* Calculate the cache index. */
cache_index = (block * nand_flash -> lx_nand_flash_pages_per_block) + page;
/* Build destination address. */
destination_ptr = &nand_flash -> lx_nand_flash_page_extra_bytes_cache[cache_index].lx_nand_page_extra_info_logical_sector;
/* Now save this in the cache. */
*destination_ptr = *((ULONG *) source);
}
/* Return status. */
return(status);
}
@@ -0,0 +1,92 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_page_erased_verify PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the driver to verify the page was erased. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block number */
/* page Page number */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* (lx_nand_flash_driver_page_erased_verify) */
/* Driver verify page erased */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_page_erased_verify(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page)
{
UINT status;
/* Increment the page erased verify count. */
nand_flash -> lx_nand_flash_diagnostic_page_erased_verifies++;
/* Call driver page erased verify function. */
status = (nand_flash -> lx_nand_flash_driver_page_erased_verify)(block, page);
/* Return status. */
return(status);
}
+180
View File
@@ -0,0 +1,180 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_read PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the driver to read data from a page. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block number */
/* page Page number */
/* destination Pointer to destination buffer */
/* words Number of words to read */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* (lx_nand_flash_driver_read) Driver page read */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_read(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *destination, ULONG words)
{
ULONG cache_index;
ULONG *source_ptr;
ULONG *destination_ptr;
ULONG i;
UINT status;
/* Determine if this is page 0. */
if (page == 0)
{
/* Determine if the page 0 cache is enabled. */
if (nand_flash -> lx_nand_flash_page_0_cache != LX_NULL)
{
/* Yes, the page 0 cache is enabled. */
/* Calculate the cache index. */
cache_index = (block * (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Determine if this cache entry is valid. */
if (nand_flash -> lx_nand_flash_page_0_cache[cache_index] != 0)
{
/* Setup the destination pointer. */
destination_ptr = (ULONG *) destination;
/* Setup the source pointer. */
source_ptr = &nand_flash -> lx_nand_flash_page_0_cache[cache_index];
/* Simply copy the page 0 information to the destination. */
i = 0;
while (i < (nand_flash -> lx_nand_flash_pages_per_block + 1))
{
/* Copy one word. */
*destination_ptr++ = *source_ptr++;
/* Move to next word. */
i++;
}
/* Increment the number of page 0 cache hits. */
nand_flash -> lx_nand_flash_diagnostic_page_0_cache_hits++;
/* Return successful status. */
status = LX_SUCCESS;
}
else
{
/* Increment the page read count. */
nand_flash -> lx_nand_flash_diagnostic_page_reads++;
/* Increment the number of page 0 cache misses. */
nand_flash -> lx_nand_flash_diagnostic_page_0_cache_misses++;
/* Call driver read function. */
status = (nand_flash -> lx_nand_flash_driver_read)(block, page, destination, words);
/* Setup destination pointer. */
destination_ptr = &nand_flash -> lx_nand_flash_page_0_cache[cache_index];
/* Setup source pointer. */
source_ptr = (ULONG *) destination;
/* Simply copy the page 0 information to the destination. */
for (i = 0; i < (nand_flash -> lx_nand_flash_pages_per_block + 1); i++)
{
/* Copy one word. */
*destination_ptr++ = *source_ptr++;
}
}
}
else
{
/* Increment the page read count. */
nand_flash -> lx_nand_flash_diagnostic_page_reads++;
/* Call driver read function. */
status = (nand_flash -> lx_nand_flash_driver_read)(block, page, destination, words);
}
}
else
{
/* Increment the page read count. */
nand_flash -> lx_nand_flash_diagnostic_page_reads++;
/* Call driver read function. */
status = (nand_flash -> lx_nand_flash_driver_read)(block, page, destination, words);
}
/* Return status. */
return(status);
}
+127
View File
@@ -0,0 +1,127 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_driver_write PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function calls the driver to write data to a NAND page. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Block number */
/* page Page number */
/* source Pointer to source buffer */
/* words Number of words to write */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* (lx_nand_flash_driver_write) Driver page write */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_driver_write(LX_NAND_FLASH *nand_flash, ULONG block, ULONG page, ULONG *source, ULONG words)
{
ULONG cache_index;
ULONG *source_ptr;
ULONG *destination_ptr;
ULONG i;
UINT status;
/* Determine if this is page 0. */
if (page == 0)
{
/* Determine if the page 0 cache is enabled. */
if (nand_flash -> lx_nand_flash_page_0_cache != LX_NULL)
{
/* Yes, the page 0 cache is enabled. */
/* Calculate the cache index. */
cache_index = (block * (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Setup destination pointer. */
destination_ptr = &nand_flash -> lx_nand_flash_page_0_cache[cache_index];
/* Setup source pointer. */
source_ptr = (ULONG *) source;
/* Simply copy the page 0 information to the destination. */
for (i = 0; i < (nand_flash -> lx_nand_flash_pages_per_block + 1); i++)
{
/* Copy one word. */
*destination_ptr++ = *source_ptr++;
}
}
}
/* Increment the page write count. */
nand_flash -> lx_nand_flash_diagnostic_page_writes++;
/* Call driver write function. */
status = (nand_flash -> lx_nand_flash_driver_write)(block, page, source, words);
/* Return status. */
return(status);
}
@@ -0,0 +1,205 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_extended_cache_enable PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function sets up the extended NAND cache for block status, */
/* page extra bytes, and page 0 contents. The routine will enable as */
/* many cache capabilities as possible until the supplied memory is */
/* exhausted. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* memory Pointer to memory for caches */
/* size Size of memory in bytes */
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_extended_cache_enable(LX_NAND_FLASH *nand_flash, VOID *memory, ULONG size)
{
UCHAR *working_ptr;
ULONG adjust_size;
ULONG i;
/* Setup the working pointer. */
working_ptr = (UCHAR *) memory;
/* Check for a NULL pointer. If NULL, disable all the caches. */
if (working_ptr == TX_NULL)
{
/* Disable all extended caches. */
nand_flash -> lx_nand_flash_block_status_cache = TX_NULL;
nand_flash -> lx_nand_flash_page_extra_bytes_cache = TX_NULL;
nand_flash -> lx_nand_flash_page_0_cache = TX_NULL;
/* Return success! */
return(LX_SUCCESS);
}
/* Determine if there is not enough memory for the block status cache. */
if (size < nand_flash -> lx_nand_flash_total_blocks)
{
/* Return an error since there is not enough memory for even the smallest
cache. */
return(LX_ERROR);
}
/* There is enough memory, setup the block status cache. */
nand_flash -> lx_nand_flash_block_status_cache = working_ptr;
/* Clear the block status cache. */
for (i = 0; i < nand_flash -> lx_nand_flash_total_blocks; i++)
{
/* Clear the block status cache. */
nand_flash -> lx_nand_flash_block_status_cache[i] = ((UCHAR) 0);
}
/* Calculate the size to adjust to achieve ULONG alignment. */
adjust_size = nand_flash -> lx_nand_flash_total_blocks + ((ULONG) (sizeof(ULONG) - 1));
adjust_size = (adjust_size/sizeof(ULONG)) * sizeof(ULONG);
/* Adjust the size. */
if (size >= adjust_size)
{
/* Subtract the aligned size. */
size = size - adjust_size;
}
else
{
/* Just set size to 0. */
size = 0;
}
/* Determine if there is enough memory for the page extra bytes cache for each page. */
if (size >= (nand_flash -> lx_nand_flash_total_pages * sizeof(LX_NAND_PAGE_EXTRA_INFO)))
{
/* Yes, there is enough memory for the extra bytes cache. */
/* First adjust the working pointer to the start of this memory. */
working_ptr = working_ptr + adjust_size;
/* Setup the pointer to page extra bytes cache. */
nand_flash -> lx_nand_flash_page_extra_bytes_cache = (LX_NAND_PAGE_EXTRA_INFO *) working_ptr;
/* Clear the page extra bytes cache. */
for (i = 0; i < nand_flash -> lx_nand_flash_total_pages; i++)
{
/* Clear the block status cache. */
nand_flash -> lx_nand_flash_page_extra_bytes_cache[i].lx_nand_page_extra_info_logical_sector = ((ULONG) 0);
}
/* Calculate the size to adjust to achieve ULONG alignment. */
adjust_size = (nand_flash -> lx_nand_flash_total_pages * sizeof(LX_NAND_PAGE_EXTRA_INFO) + ((ULONG) (sizeof(ULONG) - 1)));
adjust_size = (adjust_size/sizeof(ULONG)) * sizeof(ULONG);
/* Adjust the size. */
if (size >= adjust_size)
{
/* Subtract the aligned size. */
size = size - adjust_size;
}
else
{
/* Just set size to 0. */
size = 0;
}
}
/* Determine if there is enough memory for the page 0 cache for each block. */
if (size >= ((nand_flash -> lx_nand_flash_total_blocks * (nand_flash -> lx_nand_flash_pages_per_block + 1)) * sizeof(ULONG)))
{
/* Yes, there is enough memory for the page 0 cache. */
/* First adjust the working pointer to the start of this memory. */
working_ptr = working_ptr + adjust_size;
/* Setup the pointer to page 0 cache. */
nand_flash -> lx_nand_flash_page_0_cache = (ULONG *) working_ptr;
/* Clear the page 0 cache. */
for (i = 0; i < (nand_flash -> lx_nand_flash_total_blocks * (nand_flash -> lx_nand_flash_pages_per_block + 1)); i++)
{
/* Clear the block status cache. */
nand_flash -> lx_nand_flash_page_0_cache[i] = ((ULONG) 0);
}
}
/* Return success. */
return(LX_SUCCESS);
}
+84
View File
@@ -0,0 +1,84 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Include necessary system files. */
#include "lx_api.h"
/* Define the NAND flash opened list head and opened count. */
LX_NAND_FLASH *_lx_nand_flash_opened_ptr;
ULONG _lx_nand_flash_opened_count;
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_initialize PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function initializes the NAND flash data structures. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_initialize(void)
{
/* Clear open list head pointer and opened count. */
_lx_nand_flash_opened_ptr = LX_NULL;
_lx_nand_flash_opened_count = 0;
/* Return success! */
return(LX_SUCCESS);
}
@@ -0,0 +1,837 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_logical_sector_find PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function attempts to find the specified logical sector in */
/* the NAND flash. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* logical_sector Logical sector number */
/* superceded_check Check for page being */
/* superceded (can happen if */
/* on interruptions of page */
/* write) */
/* block Destination for block */
/* page Destination for page */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_driver_block_status_get */
/* Driver block status */
/* _lx_nand_flash_driver_extra_bytes_get Driver get extra bytes */
/* _lx_nand_flash_driver_extra_bytes_set NAND flash set extra bytes */
/* _lx_nand_flash_driver_read Driver page read */
/* _lx_nand_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_logical_sector_find(LX_NAND_FLASH *nand_flash, ULONG logical_sector, ULONG superceded_check, ULONG *block, ULONG *page)
{
LX_NAND_PAGE_EXTRA_INFO extra_info;
UCHAR block_status;
ULONG *block_word_ptr;
ULONG valid_pages;
ULONG mapped_pages;
ULONG total_blocks;
ULONG total_pages;
ULONG i, j;
ULONG search_start;
ULONG max_mapped_sector;
#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
LX_NAND_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr = LX_NULL;
LX_NAND_SECTOR_MAPPING_CACHE_ENTRY temp_sector_mapping_cache_entry;
#endif
UINT status;
/* Initialize the return parameters. */
*block = (ULONG) 0;
*page = (ULONG) 0;
/* Determine if there are any mapped pages. */
if (nand_flash -> lx_nand_flash_mapped_pages == 0)
{
/* No mapped pages so nothing can be found!. */
return(LX_SECTOR_NOT_FOUND);
}
/* Determine if this logical sector is greater than what has previously been mapped. */
if (logical_sector > nand_flash -> lx_nand_flash_max_mapped_sector)
{
/* Since this logical sector request is greater than what has been mapped previously,
there is no point in searching any further. */
/* Return sector not found status. */
return(LX_SECTOR_NOT_FOUND);
}
/* Determine if the sector mapping cache is enabled. */
if (nand_flash -> lx_nand_flash_sector_mapping_cache_enabled)
{
#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
/* Calculate the starting index of the sector cache for this sector entry. */
i = (logical_sector & LX_NAND_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NAND_SECTOR_MAPPING_CACHE_DEPTH;
/* Build a pointer to the cache entry. */
sector_mapping_cache_entry_ptr = &nand_flash -> lx_nand_flash_sector_mapping_cache[i];
/* Determine if the sector is in the sector mapping cache - assuming the depth of the sector
mapping cache is LX_NAND_SECTOR_MAPPING_CACHE_DEPTH entries. */
if ((sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Increment the sector mapping cache hit counter. */
nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_hits++;
/* Yes, return the cached values associated with the sector. */
*block = (ULONG) sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_block;
*page = (ULONG) sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_page;
/* Don't move anything since we found the entry at the top. */
/* Return a successful status. */
return(LX_SUCCESS);
}
else if (((sector_mapping_cache_entry_ptr + 1) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Increment the sector mapping cache hit counter. */
nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_hits++;
/* Yes, return the cached values associated with the sector. */
*block = (ULONG) (sector_mapping_cache_entry_ptr + 1) -> lx_nand_sector_mapping_cache_block;
*page = (ULONG) (sector_mapping_cache_entry_ptr + 1) -> lx_nand_sector_mapping_cache_page;
/* Just swap the first and second entry. */
temp_sector_mapping_cache_entry = *(sector_mapping_cache_entry_ptr);
*(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = temp_sector_mapping_cache_entry;
/* Return a successful status. */
return(LX_SUCCESS);
}
else if (((sector_mapping_cache_entry_ptr + 2) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Increment the sector mapping cache hit counter. */
nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_hits++;
/* Yes, return the cached value. */
*block = (ULONG) (sector_mapping_cache_entry_ptr + 2) -> lx_nand_sector_mapping_cache_block;
*page = (ULONG) (sector_mapping_cache_entry_ptr + 2) -> lx_nand_sector_mapping_cache_page;
/* Move the third entry to the top and the first two entries down. */
temp_sector_mapping_cache_entry = *(sector_mapping_cache_entry_ptr);
*(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = temp_sector_mapping_cache_entry;
/* Return a successful status. */
return(LX_SUCCESS);
}
else if (((sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Increment the sector mapping cache hit counter. */
nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_hits++;
/* Yes, return the cached value. */
*block = (ULONG) (sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_block;
*page = (ULONG) (sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_page;
/* Move the last entry to the top and the first three entries down. */
temp_sector_mapping_cache_entry = *(sector_mapping_cache_entry_ptr);
*(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 3);
*(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = temp_sector_mapping_cache_entry;
/* Return a successful status. */
return(LX_SUCCESS);
}
/* If we get here, we have a cache miss so increment the counter before we fall through to the search loop. */
nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_misses++;
#else
/* Direct mapping cache is defined. */
/* See if we are still opening the flash. */
if (nand_flash -> lx_nand_flash_state == LX_NAND_FLASH_OPENED)
{
/* Flash instance is opened. */
/* Determine if this logical sector fits in the logical sector direct cache mapping. */
if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE)
{
/* Yes, invalidate the logical sector cache. */
if ((nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block == 0) &&
(nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page == 0))
{
/* Entry is not mapped. */
/* No, return sector not found status. */
return(LX_SECTOR_NOT_FOUND);
}
else
{
/* Sector is mapped, return the block and page of the mapping. */
*block = nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block;
*page = nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page;
/* Return a successful status. */
return(LX_SUCCESS);
}
}
}
else
{
/* If we get here, we have a cache miss so increment the counter before we fall through to the search loop. */
nand_flash -> lx_nand_flash_diagnostic_sector_mapping_cache_misses++;
}
#endif
}
/* Clear the maximum mapped sector. */
max_mapped_sector = 0;
/* Setup the total number of mapped pages. */
mapped_pages = nand_flash -> lx_nand_flash_mapped_pages;
/* Setup pointer to internal buffer. */
block_word_ptr = nand_flash -> lx_nand_flash_page_buffer;
/* Start searching from the last found block. */
i = nand_flash -> lx_nand_flash_found_block_search;
/* Setup the starting page to look at. */
j = nand_flash -> lx_nand_flash_found_page_search;
/* Pickup the total number of blocks. */
total_blocks = nand_flash -> lx_nand_flash_total_blocks;
/* Loop through the blocks to attempt to find the mapped logical sector. */
while (total_blocks--)
{
/* First, check to make sure this block is good. */
status = _lx_nand_flash_driver_block_status_get(nand_flash, i, &block_status);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, i, 0);
/* Return the error. */
return(status);
}
/* Is this block bad? */
if (block_status != LX_NAND_GOOD_BLOCK)
{
/* Yes, this block is bad. */
/* Move to the next block. */
i++;
/* Check for wrap condition. */
if (i >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Wrap to the first block. */
i = 0;
}
/* Start looking at the first page of the next block. */
j = 1;
/* Continue to the next block. */
continue;
}
/* Read the extra bytes of page 0. This will tell us if the page has any valid mappings. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, i, 0, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, i, 0);
/* Return the error... no point in continuing. */
return(status);
}
/* Determine if there are any valid mappings. */
if (((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_BLOCK_VALID) == 0) ||
((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_BLOCK_EMPTY) != 0))
{
/* Yes, this block is either no longer valid or is empty, i.e., no mappings. */
/* Move to the next block. */
i++;
/* Check for wrap condition. */
if (i >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Wrap to the first block. */
i = 0;
}
/* Reset to the first page of the next block. */
j = 1;
/* Continue to the next block. */
continue;
}
/* Now read page 0 of the block, which has the erase count in the first 4 bytes. */
status = _lx_nand_flash_driver_read(nand_flash, i, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, i, 0);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
/* Return the error. */
return(status);
}
}
/* Determine if we have a valid logical sector mapping list. */
if ((block_word_ptr[1] != LX_NAND_PAGE_FREE) &&
(block_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] == LX_NAND_PAGE_LIST_VALID))
{
/* Yes, we have a valid logical sector mapping list in page 0. */
/* Clear the valid entries counter. */
valid_pages = 0;
/* Setup the total number of pages, less the metadata page. */
total_pages = nand_flash -> lx_nand_flash_pages_per_block - 1;
/* Now search through the sector list to find a match. */
while (total_pages--)
{
/* Is this entry valid? */
if ((block_word_ptr[j] & (LX_NAND_PAGE_VALID | LX_NAND_PAGE_MAPPING_NOT_VALID)) == LX_NAND_PAGE_VALID)
{
/* Increment the valid entries counter. */
valid_pages++;
/* Determine if this is a new maximum logical sector. */
if ((block_word_ptr[j] & LX_NAND_LOGICAL_SECTOR_MASK) > max_mapped_sector)
{
/* Yes, a new maximum mapped sectors - remember it! */
max_mapped_sector = (block_word_ptr[j] & LX_NAND_LOGICAL_SECTOR_MASK);
}
/* Do we have a valid sector match? */
if ((block_word_ptr[j] & LX_NAND_LOGICAL_SECTOR_MASK) == logical_sector)
{
/* Read in the actual page entry to make sure this logical sector mapping is still valid. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, i, j, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, i, j);
/* Return the error. */
return(status);
}
/* Verify that the actual page still has a valid sector mapping. */
if (((extra_info.lx_nand_page_extra_info_logical_sector & (LX_NAND_PAGE_VALID | LX_NAND_PAGE_MAPPING_NOT_VALID)) == LX_NAND_PAGE_VALID) &&
((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) == logical_sector))
{
/* Decrement the number of mapped pages to examine. */
mapped_pages--;
/* Determine if we care about the superceded bit. */
if (superceded_check == LX_FALSE)
{
/* Prepare the return information. */
*block = i;
*page = j;
/* Determine if the sector mapping cache is enabled. */
if (nand_flash -> lx_nand_flash_sector_mapping_cache_enabled)
{
#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
/* Yes, update the cache with the logical sector mapping. */
/* Move all the cache entries down so the oldest is at the bottom. */
*(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr);
/* Setup the new sector information in the cache. */
sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_logical_sector = (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID);
sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_block = (USHORT) i;
sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_page = (USHORT) j;
#else
/* Determine if this logical sector fits in the logical sector cache mapping. */
if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE)
{
/* Yes, store the logical sector to block/page mapping in the cache. */
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) i;
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) j;
}
#endif
}
/* Move to the next page. */
j++;
/* Determine if the page has wrapped around. */
if (j >= nand_flash -> lx_nand_flash_pages_per_block)
{
/* Yes, page wrapped. Move to page 1 of the next block. */
j = 1;
}
/* Remember the last found block and page for next search. */
nand_flash -> lx_nand_flash_found_block_search = i;
nand_flash -> lx_nand_flash_found_page_search = j;
/* Return success! */
return(LX_SUCCESS);
}
/* Check for the superceded bit being clear, which means the sector was superceded. */
else if (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_SUPERCEDED)
{
/* Prepare the return information. */
*block = i;
*page = j;
/* No need to update the cache here, since this condition only happens during initialization. */
/* Move to the next page. */
j++;
/* Determine if the page has wrapped around. */
if (j >= nand_flash -> lx_nand_flash_pages_per_block)
{
/* Yes, page wrapped. Move to page 1 of the next block. */
j = 1;
}
/* Remember the last found block and page for next search. */
nand_flash -> lx_nand_flash_found_block_search = i;
nand_flash -> lx_nand_flash_found_page_search = j;
/* Return success! */
return(LX_SUCCESS);
}
}
else
{
/* The entry is not really valid anymore, decrement the valid entries counter. */
valid_pages--;
}
}
}
/* Move to the next page. */
j++;
/* Check for wrap condition. */
if (j >= nand_flash -> lx_nand_flash_pages_per_block)
{
/* Yes, page has wrapped, reset to page 1. */
j = 1;
}
}
/* At this point we know that nothing matched in the mapping list. Now we need to check to see if there are any valid entries. */
if (valid_pages)
{
/* Reset the valid pages counter. */
valid_pages = 0;
/* Setup the total number of pages, less the metadata page. */
total_pages = nand_flash -> lx_nand_flash_pages_per_block - 1;
/* Now search through the sector list to find a match. */
while (total_pages--)
{
/* Is this entry valid? */
if ((block_word_ptr[j] & (LX_NAND_PAGE_VALID | LX_NAND_PAGE_MAPPING_NOT_VALID)) == LX_NAND_PAGE_VALID)
{
/* Read in the actual page entry to make sure this logical sector mapping is still valid. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, i, j, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, i, j);
/* Return the error. */
return(status);
}
/* Verify that the actual page still has a valid sector mapping. */
if ((extra_info.lx_nand_page_extra_info_logical_sector & (LX_NAND_PAGE_VALID | LX_NAND_PAGE_MAPPING_NOT_VALID)) == LX_NAND_PAGE_VALID)
{
/* Set the valid pages counter to 1 and break the loop. */
valid_pages = 1;
/* If one entry is valid, we can stop looking. */
break;
}
}
/* Move to the next page. */
j++;
/* Check for wrap condition. */
if (j >= nand_flash -> lx_nand_flash_pages_per_block)
{
/* Yes, page has wrapped, reset to page 1. */
j = 1;
}
}
}
/* Now, a final check for valid pages. */
if (valid_pages == 0)
{
/* There are no valid entries. We can now mark this block as not valid since there are no active
mappings. This will prevent us from examining it again during the search process. */
extra_info.lx_nand_page_extra_info_logical_sector = 0;
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, i, 0, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, i, 0);
}
/* Reset the search page to 1. */
j = 1;
}
}
else
{
/* No, we don't have a valid logical sector mapping list. */
/* Setup the total number of pages, less the metadata page. */
total_pages = nand_flash -> lx_nand_flash_pages_per_block - 1;
/* Remember the start of the search. */
search_start = j;
/* Now search through the sector list to find a match. */
while (total_pages--)
{
/* Read in the actual page entry to look for the logical sector mapping. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, i, j, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, i, j);
/* Return the error. */
return(status);
}
/* Is there a logical page mapping? */
if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE)
{
/* Since the mapping is done sequentially in the block, we know nothing
else exists after this point. */
/* Determine if the search started at the beginning of the block. */
if (search_start == 1)
{
/* Yes, we started at the beginning of the block. We are now done with this block. */
break;
}
else
{
/* Setup the new total to the search start. */
total_pages = (search_start - 1);
/* Clear search start. */
search_start = 1;
/* Start search over. */
j = 1;
continue;
}
}
/* Is this page mapping valid? */
if ((extra_info.lx_nand_page_extra_info_logical_sector & (LX_NAND_PAGE_VALID | LX_NAND_PAGE_MAPPING_NOT_VALID)) == LX_NAND_PAGE_VALID)
{
/* Yes, this page mapping is valid. */
/* Decrease the number of pages to examine. */
mapped_pages--;
/* Determine if this is a new maximum logical sector. */
if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) > max_mapped_sector)
{
/* Yes, a new maximum mapped sectors - remember it! */
max_mapped_sector = (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK);
}
/* Do we have a valid sector match? */
if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) == logical_sector)
{
/* Determine if we care about the superceded bit. */
if (superceded_check == LX_FALSE)
{
/* Prepare the return information. */
*block = i;
*page = j;
/* Determine if the sector mapping cache is enabled. */
if (nand_flash -> lx_nand_flash_sector_mapping_cache_enabled)
{
/* Yes, update the cache with the logical sector mapping. */
#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
/* Move all the cache entries down so the oldest is at the bottom. */
*(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr);
/* Setup the new sector information in the cache. */
sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_logical_sector = (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID);
sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_block = (USHORT) i;
sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_page = (USHORT) j;
#else
/* Determine if this logical sector fits in the logical sector cache mapping. */
if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE)
{
/* Yes, store the logical sector to block/page mapping in the cache. */
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) i;
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) j;
}
#endif
}
/* Move to the next page. */
j++;
/* Determine if the page has wrapped around. */
if (j >= nand_flash -> lx_nand_flash_pages_per_block)
{
/* Yes, page wrapped - move to page 1. */
j = 1;
}
/* Remember the last found block and page for next search. */
nand_flash -> lx_nand_flash_found_block_search = i;
nand_flash -> lx_nand_flash_found_page_search = j;
/* Return success! */
return(LX_SUCCESS);
}
/* Check for the superceded bit being clear, which means the sector was superceded. */
else if (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_SUPERCEDED)
{
/* Prepare the return information. */
*block = i;
*page = j;
/* No need to update the cache here, since this condition only happens during initialization. */
/* Move to the next page. */
j++;
/* Determine if the page has wrapped around. */
if (j >= nand_flash -> lx_nand_flash_pages_per_block)
{
/* Yes, page wrapped - move to page 1. */
j = 1;
}
/* Remember the last found block and page for next search. */
nand_flash -> lx_nand_flash_found_block_search = i;
nand_flash -> lx_nand_flash_found_page_search = j;
/* Return success! */
return(LX_SUCCESS);
}
}
}
/* Move to next page. */
j++;
/* Determine if we have a wrap-around condition. */
if (j >= nand_flash -> lx_nand_flash_pages_per_block)
{
/* Yes, page wrapped - move to page 1. */
j = 1;
}
}
}
/* Determine if there are any more mapped sectors. */
if (mapped_pages == 0)
break;
/* Move to the next block. */
i++;
/* Check for wrap condition. */
if (i >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Wrap to the first block. */
i = 0;
}
/* Start at the first page in the next block. */
j = 1;
}
/* Determine if we should update the maximum mapped sector. */
if (nand_flash -> lx_nand_flash_max_mapped_sector != 0xFFFFFFFF)
{
/* Yes, update the maximum mapped sector. */
nand_flash -> lx_nand_flash_max_mapped_sector = max_mapped_sector;
}
/* Return sector not found status. */
return(LX_SECTOR_NOT_FOUND);
}
@@ -0,0 +1,301 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_next_block_to_erase_find PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function finds the next block to erase in the NAND flash. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* return_erase_block Returned block to erase */
/* return_erase_count Returned erase count of block */
/* return_mapped_pages Returned number of mapped */
/* pages */
/* return_obsolete_pages Returned number of obsolete */
/* pages */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_driver_extra_bytes_get Driver block extra bytes get */
/* _lx_nand_flash_driver_block_status_get */
/* Driver block status get */
/* _lx_nand_flash_driver_read Driver page read */
/* _lx_nand_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_next_block_to_erase_find(LX_NAND_FLASH *nand_flash, ULONG *return_erase_block, ULONG *return_erase_count, ULONG *return_mapped_pages, ULONG *return_obsolete_pages)
{
LX_NAND_PAGE_EXTRA_INFO extra_info;
UCHAR block_status;
ULONG *block_word_ptr;
ULONG block;
ULONG page;
ULONG mapped_pages;
ULONG erase_count;
ULONG obsolete_pages;
ULONG min_block_erase = 0;
ULONG min_block_erase_count = 0;
ULONG min_block_obsolete_count = 0;
ULONG min_block_mapped_count = 0;
ULONG max_obsolete_pages = 0;
ULONG max_obsolete_block = 0;
ULONG max_obsolete_erase_count = 0;
ULONG max_obsolete_mapped_count = 0;
ULONG min_system_block_erase_count = 0;
ULONG max_system_block_erase_count = 0;
ULONG erase_count_threshold = 0;
UINT status;
/* Initialize the minimum erase count. */
min_block_erase_count = LX_ALL_ONES;
/* Initialize the system minimum and maximum erase counts. */
min_system_block_erase_count = LX_ALL_ONES;
max_system_block_erase_count = 0;
/* Initialize the maximum obsolete page count. */
max_obsolete_pages = 0;
/* Calculate the erase count threshold. */
if (nand_flash -> lx_nand_flash_free_pages >= nand_flash -> lx_nand_flash_pages_per_block)
{
/* Calculate erase count threshold by adding constant to the current minimum. */
erase_count_threshold = nand_flash -> lx_nand_flash_minimum_erase_count + LX_NAND_FLASH_MAX_ERASE_COUNT_DELTA;
}
else
{
/* When the number of free pages is low, simply pick the block that has the most number of obsolete sectors. */
erase_count_threshold = LX_ALL_ONES;
}
/* Set the block word pointer to the internal buffer. */
block_word_ptr = nand_flash -> lx_nand_flash_page_buffer;
/* Loop through the blocks to attempt to find the block to erase. */
for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++)
{
/* First, check to see if this block is good. */
status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return the error. */
return(status);
}
/* Determine if this block is bad. */
if (block_status != LX_NAND_GOOD_BLOCK)
{
/* Block is bad, move to the next block. */
continue;
}
/* Read page 0 of the block, the first word has the erase count. */
status = _lx_nand_flash_driver_read(nand_flash, block, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
/* Return the error. */
return(status);
}
}
/* Pickup the erase count from the first word of the block. */
erase_count = block_word_ptr[0];
/* Update the system minimum and maximum erase counts. */
if (erase_count < min_system_block_erase_count)
min_system_block_erase_count = erase_count;
if (erase_count > max_system_block_erase_count)
max_system_block_erase_count = erase_count;
/* Compute the number of obsolete and mapped pages for this block. */
obsolete_pages = 0;
mapped_pages = 0;
/* Loop through the pages for this block. */
for (page = 1; page < nand_flash -> lx_nand_flash_pages_per_block; page++)
{
/* Read the logical sector mapping for this page. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, page);
/* Return the error. */
return(status);
}
/* Is this entry free? */
if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE)
{
/* Get out of the loop, we are done! */
break;
}
/* Is this entry obsolete? */
else if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_VALID) == 0)
{
/* Increment the number of obsolete pages. */
obsolete_pages++;
}
else
{
/* Increment the number of mapped pages. */
mapped_pages++;
}
}
/* Determine if we have a block with a new maximum number of obsolete pages. */
if ((obsolete_pages > max_obsolete_pages) && (erase_count <= erase_count_threshold))
{
/* Update the new maximum obsolete pages and related information. */
max_obsolete_pages = obsolete_pages;
max_obsolete_block = block;
max_obsolete_erase_count = erase_count;
max_obsolete_mapped_count = mapped_pages;
}
else if ((max_obsolete_pages) && (obsolete_pages == max_obsolete_pages) && (erase_count <= erase_count_threshold))
{
/* Another block has the same number of obsolete pages. Does this new block have a smaller erase
count? */
if (erase_count < max_obsolete_erase_count)
{
/* Yes, choose the block with the smaller erase count. */
max_obsolete_pages = obsolete_pages;
max_obsolete_block = block;
max_obsolete_erase_count = erase_count;
max_obsolete_mapped_count = mapped_pages;
}
}
/* Determine if we have a new minimum erase count. */
if (erase_count < min_block_erase_count)
{
/* Update the new minimum erase count and related information. */
min_block_erase_count = erase_count;
min_block_erase = block;
min_block_obsolete_count = obsolete_pages;
min_block_mapped_count = mapped_pages;
}
}
/* Determine if we can erase the block with the most obsolete pages. */
if (max_obsolete_pages)
{
/* Erase the block with the most obsolete pages. */
*return_erase_block = max_obsolete_block;
*return_erase_count = max_obsolete_erase_count;
*return_obsolete_pages = max_obsolete_pages;
*return_mapped_pages = max_obsolete_mapped_count;
}
else
{
/* Otherwise, erase the block with the smallest erase count. */
*return_erase_block = min_block_erase;
*return_erase_count = min_block_erase_count;
*return_obsolete_pages = min_block_obsolete_count;
*return_mapped_pages = min_block_mapped_count;
}
/* Update the overall minimum and maximum erase count. */
nand_flash -> lx_nand_flash_minimum_erase_count = min_system_block_erase_count;
nand_flash -> lx_nand_flash_maximum_erase_count = max_system_block_erase_count;
/* Return success. */
return(LX_SUCCESS);
}
+972
View File
@@ -0,0 +1,972 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_open PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function opens a NAND flash instance and ensures the */
/* NAND flash is in a coherent state. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* name Name of NAND flash instance */
/* nand_driver_initialize Driver initialize */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* (nand_driver_initialize) Driver initialize */
/* _lx_nand_flash_driver_block_status_get */
/* Driver block status get */
/* _lx_nand_flash_driver_block_status_set */
/* Driver block status set */
/* _lx_nand_flash_driver_extra_bytes_get Driver get extra bytes */
/* _lx_nand_flash_driver_extra_bytes_set Driver set extra bytes */
/* _lx_nand_flash_driver_read Driver page read */
/* _lx_nand_flash_driver_write Driver page write */
/* _lx_nand_flash_driver_block_erased_verify */
/* Driver verify block erased */
/* _lx_nand_flash_driver_block_erase Driver block erase */
/* _lx_nand_flash_driver_page_erased_verify */
/* Driver verify page erased */
/* _lx_nand_flash_block_full_update Write mapping to page 0 */
/* _lx_nand_flash_logical_sector_find Find logical sector */
/* _lx_nand_flash_system_error System error handler */
/* tx_mutex_create Create thread-safe mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_open(LX_NAND_FLASH *nand_flash, CHAR *name, UINT (*nand_driver_initialize)(LX_NAND_FLASH *))
{
LX_NAND_PAGE_EXTRA_INFO extra_info;
ULONG block;
ULONG page;
ULONG found_block, found_page;
UCHAR block_status;
ULONG *page_word_ptr;
ULONG temp;
ULONG free_pages;
ULONG obsolete_pages;
ULONG mapped_pages;
ULONG max_mapped_sector;
ULONG erased_count, min_erased_count, max_erased_count;
UINT status;
LX_NAND_FLASH *tail_ptr;
#ifdef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
ULONG logical_sector;
#endif
TX_INTERRUPT_SAVE_AREA
LX_PARAMETER_NOT_USED(name);
/* Clear the NAND flash control block. */
TX_MEMSET(nand_flash, 0, sizeof(LX_NAND_FLASH));
/* Call the flash driver's initialization function. */
(nand_driver_initialize)(nand_flash);
/* Determine if we can support this NAND flash size. */
if (((nand_flash -> lx_nand_flash_pages_per_block * sizeof(ULONG)) + 8) > nand_flash -> lx_nand_flash_bytes_per_page)
{
/* Not enough room in page 0 to contain the erase count and logical sector mapping list. */
/* Return error. */
return(LX_ERROR);
}
/* Determine if the driver supplied a RAM buffer for reading the page. */
if (nand_flash -> lx_nand_flash_page_buffer == LX_NULL)
{
/* Return an error. */
return(LX_NO_MEMORY);
}
/* Calculate the number of words per block and per page. */
nand_flash -> lx_nand_flash_words_per_page = (nand_flash -> lx_nand_flash_bytes_per_page / sizeof(ULONG));
nand_flash -> lx_nand_flash_words_per_block = (nand_flash -> lx_nand_flash_words_per_page * nand_flash -> lx_nand_flash_pages_per_block);
/* Calculate the total pages. */
nand_flash -> lx_nand_flash_total_pages = nand_flash -> lx_nand_flash_total_blocks * nand_flash -> lx_nand_flash_pages_per_block;
/* Setup default values for the max/min erased counts. */
min_erased_count = LX_ALL_ONES;
max_erased_count = 0;
/* Default the max mapped sector to 0. */
max_mapped_sector = 0;
/* Setup the block word pointer to the internal buffer area. */
page_word_ptr = nand_flash -> lx_nand_flash_page_buffer;
/* Initialize the last found block and page search markers. */
nand_flash -> lx_nand_flash_found_block_search = 0;
nand_flash -> lx_nand_flash_found_page_search = 1;
/* Loop through the blocks to check for bad blocks and determine the minimum and maximum erase count for each good block. */
for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++)
{
/* First, check to make sure this block is good. */
status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Is this block bad? */
if (block_status != LX_NAND_GOOD_BLOCK)
{
/* Yes, this block is bad. */
/* Increment the number of bad blocks. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Continue to the next block. */
continue;
}
/* Now read page 0 of the block, which has the erase count in the first 4 bytes. */
status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
/* Return an error. */
return(LX_ERROR);
}
}
/* Is the block erased? */
if (((page_word_ptr[0] & LX_BLOCK_ERASED) != LX_BLOCK_ERASED) && (page_word_ptr[0] != LX_BLOCK_ERASE_STARTED))
{
/* No, valid block. Isolate the erased count. */
erased_count = (page_word_ptr[0] & LX_BLOCK_ERASE_COUNT_MASK);
/* Is this the new minimum? */
if (erased_count < min_erased_count)
{
/* Yes, remember the new minimum. */
min_erased_count = erased_count;
}
/* Is this the new maximum? */
if (erased_count > max_erased_count)
{
/* Yes, remember the new maximum. */
max_erased_count = erased_count;
}
}
}
/* If we haven't found any erased counts, we can assume the flash is completely erased and needs to
be setup for the first time. */
if (min_erased_count == LX_ALL_ONES)
{
/* Indicate that this is the initial format. */
nand_flash -> lx_nand_flash_diagnostic_initial_format = LX_TRUE;
/* Loop through the blocks to setup the flash the first time. */
for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++)
{
/* First, check to make sure this block is good. */
status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Is this block bad? */
if (block_status != LX_NAND_GOOD_BLOCK)
{
/* Yes, this block is bad. */
/* Increment the number of bad blocks. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Continue to the next block. */
continue;
}
/* Setup the initial erase count to 1. */
page_word_ptr[0] = (((ULONG) 1) | LX_BLOCK_ERASED);
/* Write the initial erase count for the block. */
status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
/* Check for status after the block erase. */
if (status == LX_SUCCESS)
{
/* Setup the initial erase count to 1. */
page_word_ptr[0] = ((ULONG) 1);
/* Write the initial erase count for the block. */
status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
}
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Attempt to mark this block as bad. */
status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK);
/* Check for error in setting the block status. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Increment the bad block count. */
nand_flash -> lx_nand_flash_bad_blocks++;
}
else
{
/* Update the number of free pages. Subtract 1, since page 0 is used for the erase count and list of mapped pages. */
nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages +
nand_flash -> lx_nand_flash_pages_per_block - 1;
}
}
/* Update the overall minimum and maximum erase count. */
nand_flash -> lx_nand_flash_minimum_erase_count = 1;
nand_flash -> lx_nand_flash_maximum_erase_count = 1;
}
else
{
/* At this point, we have a previously managed flash structure. This needs to be traversed to prepare for the
current flash operation. */
/* Setup the maximum mapped sector value so all searches are valid. */
nand_flash -> lx_nand_flash_max_mapped_sector = 0xFFFFFFFF;
/* Default the flash block search to an invalid value. */
nand_flash -> lx_nand_flash_free_block_search = nand_flash -> lx_nand_flash_total_blocks;
/* Loop through the blocks. */
for (block = 0; block < nand_flash -> lx_nand_flash_total_blocks; block++)
{
/* First, check to make sure this block is good. */
status = _lx_nand_flash_driver_block_status_get(nand_flash, block, &block_status);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Is this block bad? */
if (block_status != LX_NAND_GOOD_BLOCK)
{
/* Yes, this block is bad. */
/* Increment the number of bad blocks. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Continue to the next block. */
continue;
}
/* Now read page 0 of the block, which has the erase count in the first 4 bytes. */
status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
/* Return an error. */
return(LX_ERROR);
}
}
/* Is the block erased? */
if (((page_word_ptr[0] & LX_BLOCK_ERASED) == LX_BLOCK_ERASED) || (page_word_ptr[0] == LX_BLOCK_ERASE_STARTED))
{
/* This can happen if we were previously in the process of erasing the flash block and a
power interruption occurs. It should only occur once though. */
/* Is this the first time? */
if (nand_flash -> lx_nand_flash_diagnostic_erased_block)
{
/* No, this is a potential format error, since this should only happen once in a given
NAND flash format. */
_lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_BLOCK, block, 0);
}
/* Increment the erased block count. */
nand_flash -> lx_nand_flash_diagnostic_erased_block++;
/* Check to see if the block is erased. */
status = _lx_nand_flash_driver_block_erased_verify(nand_flash, block);
/* Is the block completely erased? */
if (status != LX_SUCCESS)
{
/* Is this the first time? */
if (nand_flash -> lx_nand_flash_diagnostic_re_erase_block)
{
/* No, this is a potential format error, since this should only happen once in a given
NAND flash format. */
_lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_BLOCK, block, 0);
}
/* Increment the erased block diagnostic. */
nand_flash -> lx_nand_flash_diagnostic_re_erase_block++;
/* No, the block is not fully erased, erase it again. */
status = _lx_nand_flash_driver_block_erase(nand_flash, block, max_erased_count);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Attempt to mark this block as bad. */
status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK);
/* Check for error in setting the block status. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Increment the bad block count. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Continue with next block. */
continue;
}
}
/* Now read page 0 of the block, which is all ones at this point. */
status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Attempt to mark this block as bad. */
status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK);
/* Check for error in setting the block status. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Increment the bad block count. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Continue with next block. */
continue;
}
/* Write the initial erase count for the block. */
page_word_ptr[0] = (max_erased_count | LX_BLOCK_ERASED);
status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
/* Determine if the write was successful. */
if (status == LX_SUCCESS)
{
/* Write the initial erase count for the block. */
page_word_ptr[0] = max_erased_count;
status = _lx_nand_flash_driver_write(nand_flash, block, 0, page_word_ptr, LX_NAND_ERASE_COUNT_WRITE_SIZE);
}
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Attempt to mark this block as bad. */
status = _lx_nand_flash_driver_block_status_set(nand_flash, block, LX_NAND_BAD_BLOCK);
/* Check for error in setting the block status. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Increment the bad block count. */
nand_flash -> lx_nand_flash_bad_blocks++;
/* Continue with next block. */
continue;
}
/* Update the number of free pages. */
nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages +
nand_flash -> lx_nand_flash_pages_per_block - 1;
}
else
{
/* Check for a format error, an interruption while writing the mapped sector list. */
if ((page_word_ptr[1] != LX_NAND_PAGE_FREE) &&
(page_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] != LX_NAND_PAGE_LIST_VALID))
{
/* Increment the invalid mapping counter. */
nand_flash -> lx_nand_flash_diagnostic_mapping_invalid++;
}
/* Calculate the number of free pages by traversing the pages in the block. */
free_pages = 0;
obsolete_pages = 0;
mapped_pages = 0;
for (page = 1; page < nand_flash -> lx_nand_flash_pages_per_block; page++)
{
/* Read the logical sector mapping for this page. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Return an error. */
return(LX_ERROR);
}
/* Determine if the page is free. */
if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE)
{
/* The page is free and we know that the pages are allocated sequentially
so there is no need to go further. */
/* Increment the free pages counter. */
free_pages = free_pages + (nand_flash -> lx_nand_flash_pages_per_block - page);
/* Verify that the same position in the mapped list from page 0 is also free. */
if (page_word_ptr[page] != LX_NAND_PAGE_FREE)
{
/* Increment the invalid mapping counter. */
nand_flash -> lx_nand_flash_diagnostic_mapping_invalid++;
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_FORMAT, block, page);
}
/* Determine if the associated page is really free... it could be the case that the
page data area was in the process of being written or just completed when a power
interruption occurs before the extra bytes are setup with the logical sector. */
/* Read verify the page is erased. */
status = _lx_nand_flash_driver_page_erased_verify(nand_flash, block, page);
/* Check for an error from flash driver. */
if (status == LX_ERROR)
{
/* Increment the page data not free diagnostic counter. */
nand_flash -> lx_nand_flash_diagnostic_page_data_not_free++;
/* Decrement the free page counter and increment the obsolete page counter. */
free_pages--;
obsolete_pages++;
/* Now setup the extra info to show this page is obsolete. */
extra_info.lx_nand_page_extra_info_logical_sector = 0;
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, page);
/* Return an error. */
return(LX_ERROR);
}
}
/* At this point we can break out of the page traversal loop, since nothing else can exist after this page. */
break;
}
else
{
/* Determine if the mapping list is not present and the value doesn't match the
logical sector value. */
if ((page_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] == LX_NAND_PAGE_LIST_VALID) &&
((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) !=
(page_word_ptr[page] & LX_NAND_LOGICAL_SECTOR_MASK)))
{
/* Increment the invalid mapping counter. */
nand_flash -> lx_nand_flash_diagnostic_mapping_invalid++;
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_FORMAT, block, page);
}
/* Determine if this mapped page is obsolete. */
if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) ==
extra_info.lx_nand_page_extra_info_logical_sector)
{
/* Yes, page mapping is obsolete. Increment the obsolete count. */
obsolete_pages++;
/* Continue looking at next page. */
continue;
}
/* Determine if the mapping for this page isn't yet valid. */
if (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_MAPPING_NOT_VALID)
{
/* Yes, a power interruption or reset occurred while the sector mapping entry was being written. */
/* Increment the obsolete count. */
obsolete_pages++;
/* Increment the interrupted mapping counter. */
nand_flash -> lx_nand_flash_diagnostic_mapping_write_interrupted++;
/* Invalidate this entry - clearing valid bit, superceded bit and logical sector. */
extra_info.lx_nand_page_extra_info_logical_sector = 0;
/* Write it out the page extra information. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, page);
/* Return an error. */
return(LX_ERROR);
}
/* Continue looking at next page. */
continue;
}
/* Determine if this page is still mapped. */
if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_VALID) &&
(extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_PAGE_SUPERCEDED))
{
/* Yes, sector is mapped. Increment the mapped count. */
mapped_pages++;
/* Determine if this is a new maximum mapped sector. */
if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) > max_mapped_sector)
{
/* Remember the maximum mapped logical sector. */
max_mapped_sector = (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK);
}
#ifdef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
/* Logical sector is mapped, setup the direct cache. */
logical_sector = extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK;
/* Determine if this logical sector fits in the logical sector direct cache mapping. */
if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE)
{
/* Remember the mapping for this logical sector. */
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) block;
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) page;
}
#endif
/* Continue looking at next page. */
continue;
}
/* At this point, the page was in the process of being superceded. */
/* Determine if this is a new maximum mapped sector. */
if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) > max_mapped_sector)
{
/* Remember the maximum mapped logical sector. */
max_mapped_sector = (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK);
}
/* Increment the being obsoleted count. */
nand_flash -> lx_nand_flash_diagnostic_page_being_obsoleted++;
/* Save the currently mapped pages. */
temp = nand_flash -> lx_nand_flash_mapped_pages;
/* Indicate all the pages are mapped for the purpose of this search. */
nand_flash -> lx_nand_flash_mapped_pages = nand_flash -> lx_nand_flash_total_pages;
/* Yes, this block was about to become obsolete. Perform a search for a logical sector entry that
has both of these bits set. */
_lx_nand_flash_logical_sector_find(nand_flash, (extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK),
LX_TRUE, &found_block, &found_page);
/* Read page 0 data again. */
status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
/* Return an error. */
return(LX_ERROR);
}
}
/* Restore the number of mapped pages. */
nand_flash -> lx_nand_flash_mapped_pages = temp;
/* Determine if the new logical sector entry is present. */
if (found_page)
{
/* Yes, make the current entry obsolete in favor of the new entry. */
/* Increment the obsolete count. */
obsolete_pages++;
/* Clear the valid bit. */
extra_info.lx_nand_page_extra_info_logical_sector = extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_VALID);
/* Write it out the page extra information. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, page);
/* Return an error. */
return(LX_ERROR);
}
/* Is this the first time? */
if (nand_flash -> lx_nand_flash_diagnostic_page_obsoleted)
{
/* No, this is a potential format error, since this should only happen once in a given
NAND flash format. */
_lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_SECTOR_MAP, block, page);
}
/* Increment the obsoleted count. */
nand_flash -> lx_nand_flash_diagnostic_page_obsoleted++;
#ifdef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
/* Logical sector is mapped, setup the direct cache. */
logical_sector = extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK;
/* Determine if this logical sector fits in the logical sector direct cache mapping. */
if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE)
{
/* Remember the mapping for this logical sector. */
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) found_block;
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) found_page;
}
#endif
}
else
{
/* A new page was not found. Increment the number of mapped pages. */
mapped_pages++;
#ifdef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
/* Logical sector is mapped, setup the direct cache. */
logical_sector = extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK;
/* Determine if this logical sector fits in the logical sector direct cache mapping. */
if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE)
{
/* Remember the mapping for this logical sector. */
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) block;
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) page;
}
#endif
}
}
}
/* Update the number of free, obsolete, and mapped pages. */
nand_flash -> lx_nand_flash_free_pages = nand_flash -> lx_nand_flash_free_pages + free_pages;
nand_flash -> lx_nand_flash_mapped_pages = nand_flash -> lx_nand_flash_mapped_pages + mapped_pages;
nand_flash -> lx_nand_flash_obsolete_pages = nand_flash -> lx_nand_flash_obsolete_pages + obsolete_pages;
/* Determine if the mapping list needs to be written to the flash. */
if ((free_pages == 0) && (page_word_ptr[1] == LX_ALL_ONES))
{
/* Yes, the mapping list should be written to page 0. */
_lx_nand_flash_block_full_update(nand_flash, block, page_word_ptr[0]);
/* Read page 0 data again. */
status = _lx_nand_flash_driver_read(nand_flash, block, 0, page_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, block, 0);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
/* Return an error. */
return(LX_ERROR);
}
}
}
}
}
/* Update the overall minimum and maximum erase count. */
nand_flash -> lx_nand_flash_minimum_erase_count = min_erased_count;
nand_flash -> lx_nand_flash_maximum_erase_count = max_erased_count;
/* Determine if we need to update the free sector search pointer. */
if (nand_flash -> lx_nand_flash_free_block_search == nand_flash -> lx_nand_flash_total_blocks)
{
/* Just start at the beginning. */
nand_flash -> lx_nand_flash_free_block_search = 0;
}
}
#ifdef LX_THREAD_SAFE_ENABLE
/* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs
in order to provide thread-safe operation. */
status = tx_mutex_create(&nand_flash -> lx_nand_flash_mutex, "NAND Flash Mutex", TX_NO_INHERIT);
/* Determine if the mutex creation encountered an error. */
if (status != TX_SUCCESS)
{
/* Call system error handler, since this should not happen. */
_lx_nand_flash_system_error(nand_flash, LX_SYSTEM_MUTEX_CREATE_FAILED, 0, 0);
/* Return error to caller. */
return(LX_ERROR);
}
#endif
/* Enable the sector mapping cache. */
nand_flash -> lx_nand_flash_sector_mapping_cache_enabled = LX_TRUE;
/* Initialize the last found block and page search markers. */
nand_flash -> lx_nand_flash_found_block_search = 0;
nand_flash -> lx_nand_flash_found_page_search = 1;
/* Remember the maximum mapped sector. */
nand_flash -> lx_nand_flash_max_mapped_sector = max_mapped_sector;
/* Lockout interrupts. */
TX_DISABLE
/* At this point, the NAND flash has been opened successfully. Place the
NAND flash control block on the linked list of currently opened NAND flashes. */
/* Set the NAND flash state to open. */
nand_flash -> lx_nand_flash_state = LX_NAND_FLASH_OPENED;
/* Place the NAND flash control block on the list of opened NAND flashes. First,
check for an empty list. */
if (_lx_nand_flash_opened_count)
{
/* List is not empty - other NAND flashes are open. */
/* Pickup tail pointer. */
tail_ptr = _lx_nand_flash_opened_ptr -> lx_nand_flash_open_previous;
/* Place the new NAND flash control block in the list. */
_lx_nand_flash_opened_ptr -> lx_nand_flash_open_previous = nand_flash;
tail_ptr -> lx_nand_flash_open_next = nand_flash;
/* Setup this NAND flash's opened links. */
nand_flash -> lx_nand_flash_open_previous = tail_ptr;
nand_flash -> lx_nand_flash_open_next = _lx_nand_flash_opened_ptr;
}
else
{
/* The opened NAND flash list is empty. Add the NAND flash to empty list. */
_lx_nand_flash_opened_ptr = nand_flash;
nand_flash -> lx_nand_flash_open_next = nand_flash;
nand_flash -> lx_nand_flash_open_previous = nand_flash;
}
/* Increment the opened NAND flash counter. */
_lx_nand_flash_opened_count++;
/* Restore interrupts. */
TX_RESTORE
/* Return a successful completion. */
return(LX_SUCCESS);
}
+130
View File
@@ -0,0 +1,130 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_page_ecc_check PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks the NAND page and ECC for errors and */
/* attempts to correct 1 bit errors. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* page_buffer Page buffer */
/* ecc_buffer Returned ECC buffer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_256byte_ecc_check Check 256 bytes and ECC */
/* */
/* CALLED BY */
/* */
/* NAND flash driver */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_page_ecc_check(LX_NAND_FLASH *nand_flash, UCHAR *page_buffer, UCHAR *ecc_buffer)
{
UINT bytes_checked;
UINT status;
UINT return_status = LX_SUCCESS;
/* Loop to check the entire NAND flash page. */
bytes_checked = 0;
while (bytes_checked < nand_flash -> lx_nand_flash_bytes_per_page)
{
/* Check this 256 byte piece of the NAND page. */
status = _lx_nand_flash_256byte_ecc_check(page_buffer, ecc_buffer);
/* Determine if there was an error. */
if (status != LX_SUCCESS)
{
/* Determine if a non-correctable error is present. */
if (status == LX_NAND_ERROR_NOT_CORRECTED)
{
/* Always return a non-correctable error, if present. */
return_status = LX_NAND_ERROR_NOT_CORRECTED;
break;
}
/* A single-bit error was corrected, return this status
if there is no LX_ERROR status already detected. */
else if (return_status == LX_SUCCESS)
{
/* Return a notice that the single bit error was corrected. */
return_status = LX_NAND_ERROR_CORRECTED;
}
}
/* Move to the next 256 byte portion of the page. */
bytes_checked = bytes_checked + 256;
/* Move the page buffer forward. */
page_buffer = page_buffer + 256;
/* Move the ECC buffer forward, note there are 3 bytes of ECC per page. */
ecc_buffer = ecc_buffer + 3;
}
/* Return status. */
return(return_status);
}
+104
View File
@@ -0,0 +1,104 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_page_ecc_compute PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function computes the ECC for a NAND flash page. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* page_buffer Page buffer */
/* ecc_buffer Returned ECC buffer */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_256byte_ecc_compute Compute ECC for 256 bytes */
/* */
/* CALLED BY */
/* */
/* NAND flash driver */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_page_ecc_compute(LX_NAND_FLASH *nand_flash, UCHAR *page_buffer, UCHAR *ecc_buffer)
{
UINT bytes_computed;
/* Loop to compute the ECC over the entire NAND flash page. */
bytes_computed = 0;
while (bytes_computed < nand_flash -> lx_nand_flash_bytes_per_page)
{
/* Compute the ECC for this 256 byte piece of the page. */
_lx_nand_flash_256byte_ecc_compute(page_buffer, ecc_buffer);
/* Move to the next 256 byte portion of the page. */
bytes_computed = bytes_computed + 256;
/* Move the page buffer forward. */
page_buffer = page_buffer + 256;
/* Move the ECC buffer forward, note there are 3 bytes of ECC per page. */
ecc_buffer = ecc_buffer + 3;
}
/* Return success. */
return(LX_SUCCESS);
}
@@ -0,0 +1,123 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_partial_defragment PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function defragments the NAND flash up to the specified */
/* number of blocks. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* max_blocks Maximum number of blocks to */
/* defragment */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_block_reclaim Reclaim a NAND flash block */
/* tx_mutex_get Get thread protection */
/* tx_mutex_put Release thread protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_partial_defragment(LX_NAND_FLASH *nand_flash, UINT max_blocks)
{
ULONG i;
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Determine if the maximum number of blocks exceeds the total blocks in this flash instance. */
if (max_blocks >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Adjust the maximum to the total number of blocks. */
max_blocks = nand_flash -> lx_nand_flash_total_blocks;
}
/* Loop for max number of blocks, while there are obsolete count. */
for (i = 0; i < max_blocks; i++)
{
/* Determine if there is any more defragment work. */
if (nand_flash -> lx_nand_flash_obsolete_pages == 0)
break;
/* Call the block reclaim function to defragment. */
_lx_nand_flash_block_reclaim(nand_flash);
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return successful completion. */
return(LX_SUCCESS);
}
@@ -0,0 +1,392 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_physical_page_allocate PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function allocates a free page for mapping to a */
/* logical sector. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* block Destination for block */
/* page Destination for page */
/* erase_count Destination for erase count */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_driver_extra_bytes_get Driver get extra bytes */
/* _lx_nand_flash_driver_extra_bytes_set Driver set extra bytes */
/* _lx_nand_flash_driver_block_status_get */
/* Driver block status get */
/* _lx_nand_flash_driver_page_erased_verify */
/* Driver verify page erased */
/* _lx_nand_flash_driver_read Driver page read */
/* _lx_nand_flash_block_full_update Update page 0 with list of */
/* mapped pages */
/* _lx_nand_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_physical_page_allocate(LX_NAND_FLASH *nand_flash, ULONG *block, ULONG *page, ULONG *erase_count)
{
LX_NAND_PAGE_EXTRA_INFO extra_info;
UCHAR block_status;
ULONG search_block;
ULONG search_page;
ULONG *word_ptr;
ULONG i, j;
UINT status;
/* Increment the number of page allocation requests. */
nand_flash -> lx_nand_flash_diagnostic_page_allocates++;
/* Initialize the return parameters. */
*block = (ULONG) 0;
*page = (ULONG) 0;
*erase_count = nand_flash -> lx_nand_flash_minimum_erase_count;
/* Determine if there are any free pages. */
if (nand_flash -> lx_nand_flash_free_pages == 0)
{
/* Increment the number of failed allocations. */
nand_flash -> lx_nand_flash_diagnostic_page_allocate_errors++;
/* No free pages, return . */
return(LX_NO_PAGES);
}
/* Pickup the search for a free page at the specified block. */
search_block = nand_flash -> lx_nand_flash_free_block_search;
/* Loop through the blocks to find a free page. */
for (i = 0; i < nand_flash -> lx_nand_flash_total_blocks; i++)
{
/* First, check to see if this block is good. */
status = _lx_nand_flash_driver_block_status_get(nand_flash, search_block, &block_status);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, search_block, 0);
/* Return the error. */
return(status);
}
/* Determine if this block is bad. */
if (block_status != LX_NAND_GOOD_BLOCK)
{
/* Move to next search block. */
search_block++;
/* Have we wrapped around yet? */
if (search_block >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Reset the search block to the beginning. */
search_block = 0;
}
/* Block is bad, move to the next block. */
continue;
}
/* Read the extra bytes of page 0. This will tell us if the page has any free entries. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, search_block, 0, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, search_block, 0);
/* Return the error... no point in continuing. */
return(status);
}
/* Determine if there are any free entries. */
if ((extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_BLOCK_FULL) == 0)
{
/* This block is full... go to the next block. */
search_block++;
/* Have we wrapped around yet? */
if (search_block >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Reset the search block to the beginning. */
search_block = 0;
}
/* Block is bad, move to the next block. */
continue;
}
/* Now check to see if page 0 has been written to. When the block is full, page 0 is written with the mapping of pages
to logical sectors in this block - only when the block becomes full. If the block has additional pages free, page 0 is all 0xFFs. */
status = _lx_nand_flash_driver_read(nand_flash, search_block, 0, nand_flash -> lx_nand_flash_page_buffer, nand_flash -> lx_nand_flash_words_per_page);
/* Check for an error... an error here indicates the block does not have any free pages. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, search_block, 0);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
/* Return the error. */
return(status);
}
}
/* Setup pointer to the page 0 data. */
word_ptr = nand_flash -> lx_nand_flash_page_buffer;
/* Pickup the block erase count (first word in the page 0 data area). */
if (*word_ptr != LX_ALL_ONES)
*erase_count = *word_ptr;
/* Now determine if the remaining words are all ones, i.e. haven't been written to. */
j = 1;
while (j < (nand_flash -> lx_nand_flash_pages_per_block + 1))
{
/* Has this word been written to? */
if (word_ptr[j] != LX_ALL_ONES)
break;
/* Move to next word. */
j++;
}
/* Does this block have any free pages? */
if (j < (nand_flash -> lx_nand_flash_pages_per_block + 1))
{
/* Move to next search block. */
search_block++;
/* Have we wrapped around yet? */
if (search_block >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Reset the search block to the beginning. */
search_block = 0;
}
/* No, the data area has been written to. Simply move to the next block. */
continue;
}
/* Now search for an available page within the block. */
search_page = 1;
while (search_page < nand_flash -> lx_nand_flash_pages_per_block)
{
/* Read the extra information for this page to see if there is a sector mapping. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, search_block, search_page, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, search_block, search_page);
/* Return the error. */
return(status);
}
/* Now determine if this page is mapped or free. */
if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE)
{
/* Now make sure the data area of this page is free. */
status = _lx_nand_flash_driver_page_erased_verify(nand_flash, search_block, search_page);
/* Is the page free? */
if (status != LX_SUCCESS)
{
/* No, the page is not actually free. For now, simply mark the extra info area to indicate
the page is not available and continue our search. */
extra_info.lx_nand_page_extra_info_logical_sector = 0;
/* Decrease the number of free pages. */
nand_flash -> lx_nand_flash_free_pages--;
/* Increase the number of obsolete pages. */
nand_flash -> lx_nand_flash_obsolete_pages++;
/* Write out the extra info for this page. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, search_block, search_page, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, search_block, search_page);
/* Return the error. */
return(status);
}
/* Determine if this is the last entry of the block. */
if (search_page == (nand_flash -> lx_nand_flash_pages_per_block - 1))
{
/* Yes, we need to update page 0 of the block with the list of mapped
pages for this block. */
_lx_nand_flash_block_full_update(nand_flash, search_block, *erase_count);
}
}
else
{
/* Yes, we have found a free page in this block. Get out of the page search loop. */
break;
}
}
/* Move to next search page. */
search_page++;
}
/* Determine if we have found the free block. */
if (search_page < nand_flash -> lx_nand_flash_pages_per_block)
{
/* Remember the block to search. */
nand_flash -> lx_nand_flash_free_block_search = search_block;
/* Determine if the allocated page is the last one in this block. */
if (search_page == (nand_flash -> lx_nand_flash_pages_per_block - 1))
{
/* Yes, move to the next block. */
nand_flash -> lx_nand_flash_free_block_search++;
/* Have we wrapped around yet? */
if (nand_flash -> lx_nand_flash_free_block_search >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Wrap condition - reset the search block to the beginning. */
nand_flash -> lx_nand_flash_free_block_search = 0;
}
}
/* Prepare the return information. */
*block = search_block;
*page = search_page;
/* Determine if this is the first data page of the block. */
if (search_page == 1)
{
/* Yes, we need to update the extra bytes of page 0 to indicate the block is no longer empty. */
extra_info.lx_nand_page_extra_info_logical_sector = ((ULONG) LX_NAND_PAGE_FREE) & ~((ULONG) LX_NAND_BLOCK_EMPTY);
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, search_block, 0, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, search_block, 0);
}
}
/* Return success! */
return(LX_SUCCESS);
}
/* Move to next search block. */
search_block++;
/* Have we wrapped around yet? */
if (search_block >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Reset the search block to the beginning. */
search_block = 0;
}
}
/* Increment the number of failed allocations. */
nand_flash -> lx_nand_flash_diagnostic_page_allocate_errors++;
/* Return error. */
return(LX_NO_PAGES);
}
@@ -0,0 +1,150 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_sector_mapping_cache_invalidate PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function invalidates the sector's entry in the NAND flash */
/* cache. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* logical_sector Logical sector */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
VOID _lx_nand_flash_sector_mapping_cache_invalidate(LX_NAND_FLASH *nand_flash, ULONG logical_sector)
{
#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
ULONG i;
LX_NAND_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr;
#endif
/* Determine if the sector mapping cache is enabled. */
if (nand_flash -> lx_nand_flash_sector_mapping_cache_enabled)
{
#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
/* Calculate the starting index of the sector mapping cache for this sector entry. */
i = (logical_sector & LX_NAND_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NAND_SECTOR_MAPPING_CACHE_DEPTH;
/* Build a pointer to the cache entry. */
sector_mapping_cache_entry_ptr = &nand_flash -> lx_nand_flash_sector_mapping_cache[i];
/* Determine if the sector is in the sector mapping cache - assuming the depth of the sector
mapping cache is LX_NAND_SECTOR_MAPPING_CACHE_DEPTH entries. */
if ((sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Move all cache entries up and invalidate the last entry. */
*(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 3);
/* Invalidate the last entry. */
(sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector = 0;
}
else if (((sector_mapping_cache_entry_ptr + 1) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Move all subsequent cache entries up and invalidate the last entry. */
*(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 3);
/* Invalidate the last entry. */
(sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector = 0;
}
else if (((sector_mapping_cache_entry_ptr + 2) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Move all subsequent cache entries up and invalidate the last entry. */
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 3);
/* Invalidate the last entry. */
(sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector = 0;
}
else if (((sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector) == (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Simply invalidate the last entry. */
(sector_mapping_cache_entry_ptr + 3) -> lx_nand_sector_mapping_cache_logical_sector = 0;
}
#else
/* Direct mapping cache is defined. */
/* Determine if this logical sector fits in the logical sector cache mapping. */
if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE)
{
/* Yes, invalidate the logical sector cache. */
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = 0;
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = 0;
}
#endif
}
}
+173
View File
@@ -0,0 +1,173 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_sector_read PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reads a logical sector from NAND flash. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* logical_sector Logical sector number */
/* buffer Pointer to buffer to read into*/
/* (the size is number of */
/* bytes in a page) */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_driver_read Driver page read */
/* _lx_nand_flash_logical_sector_find Find logical sector */
/* _lx_nand_flash_system_error Internal system error handler */
/* tx_mutex_get Get thread protection */
/* tx_mutex_put Release thread protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_sector_read(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer)
{
UINT status;
ULONG found_block;
ULONG found_page;
ULONG i;
ULONG *word_ptr;
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Increment the number of read requests. */
nand_flash -> lx_nand_flash_diagnostic_sector_read_requests++;
/* See if we can find the sector in the current mapping. */
_lx_nand_flash_logical_sector_find(nand_flash, logical_sector, LX_FALSE, &found_block, &found_page);
/* Determine if the logical sector mapping was found. */
if (found_page)
{
/* Yes, we were able to find the logical sector to page mapping. */
/* Read the data from the page. */
status = _lx_nand_flash_driver_read(nand_flash, found_block, found_page, buffer, nand_flash -> lx_nand_flash_words_per_page);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, found_block, found_page);
/* Determine if the error was corrected. */
if (status == LX_NAND_ERROR_CORRECTED)
{
/* Yes, we were able to read this page successfully with error correction. */
/* Change the status to LX_SUCCESS. */
status = LX_SUCCESS;
}
else
{
/* Adjust return status. */
status = LX_ERROR;
}
}
else
{
/* Set the status to success. */
status = LX_SUCCESS;
}
}
else
{
/* Sector hasn't been written. Simply fill the destination buffer with ones and return success. */
/* Setup pointer to users buffer. */
word_ptr = (ULONG *) buffer;
/* Put all ones in he buffer. */
for (i = 0; i < nand_flash -> lx_nand_flash_words_per_page; i++)
{
/* Copy a word. */
*word_ptr++ = LX_ALL_ONES;
}
/* Set the status to success. */
status = LX_SUCCESS;
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return status. */
return(status);
}
+268
View File
@@ -0,0 +1,268 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_sector_release PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function releases a logical sector from being managed in the */
/* NAND flash. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* logical_sector Logical sector number */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_driver_read Driver flash sector read */
/* _lx_nand_flash_driver_write Driver flash sector write */
/* _lx_nand_flash_driver_extra_bytes_get Get extra bytes from spare */
/* _lx_nand_flash_driver_extra_bytes_set Set extra bytes in spare */
/* _lx_nand_flash_block_obsoleted_check Check for block obsoleted */
/* _lx_nand_flash_block_reclaim Reclaim one flash block */
/* _lx_nand_flash_sector_mapping_cache_invalidate */
/* Invalidate cache entry */
/* _lx_nand_flash_logical_sector_find Find logical sector */
/* _lx_nand_flash_system_error Internal system error handler */
/* tx_mutex_get Get thread protection */
/* tx_mutex_put Release thread protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_sector_release(LX_NAND_FLASH *nand_flash, ULONG logical_sector)
{
LX_NAND_PAGE_EXTRA_INFO extra_info;
UINT status;
ULONG found_block;
ULONG found_page;
ULONG *block_word_ptr;
ULONG i;
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Increment the number of release requests. */
nand_flash -> lx_nand_flash_diagnostic_sector_release_requests++;
/* See if we can find the logical sector in the current mapping. */
_lx_nand_flash_logical_sector_find(nand_flash, logical_sector, LX_FALSE, &found_block, &found_page);
/* Determine if the logical sector to page mapping was found. */
if (found_page)
{
/* Yes, we were able to find the logical sector. */
/* Determine if this sector is the current maximum sector. */
if (nand_flash -> lx_nand_flash_max_mapped_sector == logical_sector)
{
/* Yes, this is the maximum sector. Reduce the maximum, if possible. */
if (logical_sector)
{
/* Decrement the logical sector. */
nand_flash -> lx_nand_flash_max_mapped_sector--;
}
}
/* Read the extra information from the page. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, found_block, found_page, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, found_block, found_page);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return an error. */
return(LX_ERROR);
}
/* Mark this sector as invalid. */
/* Now clear bits 31 and 30, which indicates this sector is now obsoleted. */
extra_info.lx_nand_page_extra_info_logical_sector = extra_info.lx_nand_page_extra_info_logical_sector &
~(((ULONG) LX_NAND_PAGE_VALID) | ((ULONG) LX_NAND_PAGE_SUPERCEDED));
/* Write the value back to the flash to clear bits 31 & 30. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, found_block, found_page, (UCHAR *) &extra_info, sizeof(extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, found_block, found_page);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return an error. */
return(LX_ERROR);
}
/* Increment the number of obsolete pages. */
nand_flash -> lx_nand_flash_obsolete_pages++;
/* Decrement the number of mapped pages. */
nand_flash -> lx_nand_flash_mapped_pages--;
/* Setup pointer to internal buffer. */
block_word_ptr = nand_flash -> lx_nand_flash_page_buffer;
/* Now read page 0 of the block, which has the erase count in the first 4 bytes. */
status = _lx_nand_flash_driver_read(nand_flash, found_block, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, found_block, 0);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return the error. */
return(status);
}
}
#ifndef LX_NAND_FLASH_MAPPING_LIST_UPDATE_DISABLE
/* Determine if the mapping list in page 0 is valid. */
if ((block_word_ptr[1] != LX_NAND_PAGE_FREE) &&
(block_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] == LX_NAND_PAGE_LIST_VALID))
{
/* Mark the entry as invalid. */
block_word_ptr[found_page] &= ~LX_NAND_PAGE_VALID;
/* Write the invalid entry. */
status = _lx_nand_flash_driver_write(nand_flash, found_block, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
}
#endif
/* Ensure the sector mapping cache no longer has this sector. */
_lx_nand_flash_sector_mapping_cache_invalidate(nand_flash, logical_sector);
/* Call routine to see if this block is completely obsoleted. If so,
we can reclaim it immediately. */
_lx_nand_flash_block_obsoleted_check(nand_flash, found_block);
/* Determine if there are less than two block's worth of free pages. */
i = 0;
while (nand_flash -> lx_nand_flash_free_pages <= nand_flash -> lx_nand_flash_pages_per_block)
{
/* Attempt to reclaim one block. */
_lx_nand_flash_block_reclaim(nand_flash);
/* Increment the block count. */
i++;
/* Have we exceeded the number of blocks in the system? */
if (i >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Yes, break out of the loop. */
break;
}
}
}
else
{
/* Could not find the logical sector. */
status = LX_SECTOR_NOT_FOUND;
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return status. */
return(status);
}
+458
View File
@@ -0,0 +1,458 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_sector_write PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function writes a logical sector to the NAND flash page. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* logical_sector Logical sector number */
/* buffer Pointer to buffer to write */
/* (the size is number of */
/* bytes in a page) */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nand_flash_driver_read Driver flash sector read */
/* _lx_nand_flash_driver_write Driver flash sector write */
/* _lx_nand_flash_driver_extra_bytes_get Get extra bytes from spare */
/* _lx_nand_flash_driver_extra_bytes_set Set extra bytes in spare */
/* _lx_nand_flash_block_full_update Update page 0 with list of */
/* mapped pages */
/* _lx_nand_flash_block_obsoleted_check Check for block obsoleted */
/* _lx_nand_flash_block_reclaim Reclaim one flash block */
/* _lx_nand_flash_logical_sector_find Find logical sector */
/* _lx_nand_flash_physical_page_allocate Allocate new page */
/* _lx_nand_flash_sector_mapping_cache_invalidate */
/* Invalidate cache entry */
/* _lx_nand_flash_system_error Internal system error handler */
/* tx_mutex_get Get thread protection */
/* tx_mutex_put Release thread protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nand_flash_sector_write(LX_NAND_FLASH *nand_flash, ULONG logical_sector, VOID *buffer)
{
LX_NAND_PAGE_EXTRA_INFO old_extra_info;
LX_NAND_PAGE_EXTRA_INFO new_extra_info;
ULONG old_block;
ULONG old_page;
ULONG new_block;
ULONG new_page;
ULONG new_erase_count;
ULONG i;
#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
LX_NAND_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr;
#endif
UINT status;
ULONG *block_word_ptr;
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nand_flash -> lx_nand_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Determine if there are less than two block's worth of free pages. */
i = 0;
while (nand_flash -> lx_nand_flash_free_pages <= nand_flash -> lx_nand_flash_pages_per_block)
{
/* Attempt to reclaim one block. */
_lx_nand_flash_block_reclaim(nand_flash);
/* Increment the block count. */
i++;
/* Have we exceeded the number of blocks in the system? */
if (i >= nand_flash -> lx_nand_flash_total_blocks)
{
/* Yes, break out of the loop. */
break;
}
}
/* Increment the number of write requests. */
nand_flash -> lx_nand_flash_diagnostic_sector_write_requests++;
/* See if we can find the logical sector in the current mapping. */
_lx_nand_flash_logical_sector_find(nand_flash, logical_sector, LX_FALSE, &old_block, &old_page);
/* Allocate a new page for this write. */
_lx_nand_flash_physical_page_allocate(nand_flash, &new_block, &new_page, &new_erase_count);
/* Determine if the new page allocation was successful. */
if (new_page)
{
/* Yes, we were able to allocate a new page. */
/* Determine if this is the new maximum mapped sector. */
if (logical_sector > nand_flash -> lx_nand_flash_max_mapped_sector)
{
/* Remember this maximum mapped sector. */
nand_flash -> lx_nand_flash_max_mapped_sector = logical_sector;
}
/* Update the number of free pages. */
nand_flash -> lx_nand_flash_free_pages--;
/* Write the logical sector data to the new page. */
status = _lx_nand_flash_driver_write(nand_flash, new_block, new_page, buffer, nand_flash -> lx_nand_flash_words_per_page);
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, new_block, new_page);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return an error. */
return(LX_ERROR);
}
/* Determine if there was an old mapping. */
if (old_page)
{
/* Read the extra info of the old page. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, old_block, old_page, (UCHAR *) &old_extra_info, sizeof(old_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, old_block, old_page);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return an error. */
return(LX_ERROR);
}
/* Clear bit 30, which indicates this sector is superceded. */
old_extra_info.lx_nand_page_extra_info_logical_sector = old_extra_info.lx_nand_page_extra_info_logical_sector & (~((ULONG) LX_NAND_PAGE_SUPERCEDED));
/* Write the extra info to old page. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, old_block, old_page, (UCHAR *) &old_extra_info, sizeof(old_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, old_block, old_page);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return an error. */
return(LX_ERROR);
}
}
/* Now build the new mapping entry - with the not valid bit set initially. */
new_extra_info.lx_nand_page_extra_info_logical_sector = ((ULONG) LX_NAND_PAGE_VALID) | ((ULONG) LX_NAND_PAGE_SUPERCEDED) | ((ULONG) LX_NAND_PAGE_MAPPING_NOT_VALID) | logical_sector;
/* Write out the new mapping entry. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, new_block, new_page, (UCHAR *) &new_extra_info, sizeof(new_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, new_block, new_page);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return an error. */
return(LX_ERROR);
}
/* Now clear the not valid bit to make this sector mapping valid. This is done because the writing of the extra bytes itself can
be interrupted and we need to make sure this can be detected when the flash is opened again. */
new_extra_info.lx_nand_page_extra_info_logical_sector = new_extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_MAPPING_NOT_VALID);
/* Clear the not valid bit. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, new_block, new_page, (UCHAR *) &new_extra_info, sizeof(new_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, new_block, new_page);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return an error. */
return(LX_ERROR);
}
/* Increment the number of mapped sectors. */
nand_flash -> lx_nand_flash_mapped_pages++;
/* Was there a previously mapped sector? */
if (old_page)
{
/* Now clear bit 31, which indicates this sector is now obsoleted. */
old_extra_info.lx_nand_page_extra_info_logical_sector = old_extra_info.lx_nand_page_extra_info_logical_sector & ~((ULONG) LX_NAND_PAGE_VALID);
/* Write the value back to the flash to clear bit 31. */
status = _lx_nand_flash_driver_extra_bytes_set(nand_flash, old_block, old_page, (UCHAR *) &old_extra_info, sizeof(old_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, old_block, old_page);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return an error. */
return(LX_ERROR);
}
/* Setup pointer to internal buffer. */
block_word_ptr = nand_flash -> lx_nand_flash_page_buffer;
/* Now read page 0 of the block, which has the erase count in the first 4 bytes. */
status = _lx_nand_flash_driver_read(nand_flash, old_block, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, old_block, 0);
/* Determine if the error is fatal. */
if (status != LX_NAND_ERROR_CORRECTED)
{
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return the error. */
return(status);
}
}
#ifndef LX_NAND_FLASH_MAPPING_LIST_UPDATE_DISABLE
/* Determine if there is a valid mapping list. */
if ((block_word_ptr[1] != LX_NAND_PAGE_FREE) &&
(block_word_ptr[nand_flash -> lx_nand_flash_pages_per_block] == LX_NAND_PAGE_LIST_VALID))
{
/* Mark the entry as invalid. */
block_word_ptr[old_page] &= ~LX_NAND_PAGE_VALID;
/* Invalidate the page. */
status = _lx_nand_flash_driver_write(nand_flash, old_block, 0, block_word_ptr, (nand_flash -> lx_nand_flash_pages_per_block + 1));
}
#endif
/* Increment the number of obsolete pages. */
nand_flash -> lx_nand_flash_obsolete_pages++;
/* Decrement the number of mapped pages. */
nand_flash -> lx_nand_flash_mapped_pages--;
/* Invalidate the old sector mapping cache entry. */
_lx_nand_flash_sector_mapping_cache_invalidate(nand_flash, logical_sector);
/* Call routine to see if this block is completely obsoleted. If so,
we can reclaim it immediately. */
_lx_nand_flash_block_obsoleted_check(nand_flash, old_block);
}
/* Read the extra info of the old page. */
status = _lx_nand_flash_driver_extra_bytes_get(nand_flash, new_block, new_page, (UCHAR *) &new_extra_info, sizeof(new_extra_info));
/* Check for an error from flash driver. */
if (status)
{
/* Call system error handler. */
_lx_nand_flash_system_error(nand_flash, status, old_block, old_page);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return an error. */
return(LX_ERROR);
}
/* Check to see if the logical sector is still mapped to the same block/page. */
if (((new_extra_info.lx_nand_page_extra_info_logical_sector & LX_NAND_LOGICAL_SECTOR_MASK) == logical_sector) &&
(new_extra_info.lx_nand_page_extra_info_logical_sector & ((ULONG) LX_NAND_PAGE_VALID)))
{
/* Determine if the new page is the last page of the block. */
if (new_page == (nand_flash -> lx_nand_flash_pages_per_block - 1))
{
/* Yes, we need to update page 0 of the block with the list of mapped
pages for this block. */
_lx_nand_flash_block_full_update(nand_flash, new_block, new_erase_count);
}
/* Determine if the logical sector mapping cache is enabled. */
if (nand_flash -> lx_nand_flash_sector_mapping_cache_enabled)
{
/* Yes, sector mapping cache is enabled, place this logical sector mapping information in the cache. */
#ifndef LX_NAND_FLASH_DIRECT_MAPPING_CACHE
/* Calculate the starting index of the sector mapping cache for this sector entry. */
i = (logical_sector & LX_NAND_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NAND_SECTOR_MAPPING_CACHE_DEPTH;
/* Build a pointer to the cache entry. */
sector_mapping_cache_entry_ptr = &nand_flash -> lx_nand_flash_sector_mapping_cache[i];
/* Move all the cache entries down so the oldest is at the bottom. */
*(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr);
/* Setup the new logical sector information in the cache. */
sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_logical_sector = (logical_sector | LX_NAND_SECTOR_MAPPING_CACHE_ENTRY_VALID);
sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_block = (USHORT) new_block;
sector_mapping_cache_entry_ptr -> lx_nand_sector_mapping_cache_page = (USHORT) new_page;
#else
/* Determine if this logical sector fits in the logical sector cache mapping. */
if (logical_sector < LX_NAND_SECTOR_MAPPING_CACHE_SIZE)
{
/* Yes, store the logical sector to block/page mapping in the cache. */
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_block = (USHORT) new_block;
nand_flash -> lx_nand_flash_sector_mapping_cache[logical_sector].lx_nand_sector_mapping_cache_page = (USHORT) new_page;
}
#endif
}
}
/* Indicate the write was successful. */
status = LX_SUCCESS;
}
else
{
/* Indicate the write was unsuccessful. */
status = LX_NO_SECTORS;
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nand_flash -> lx_nand_flash_mutex);
#endif
/* Return the completion status. */
return(status);
}
+398
View File
@@ -0,0 +1,398 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash Simulator */
/** */
/**************************************************************************/
/**************************************************************************/
/* Include necessary files. */
#include "tx_api.h"
#include "lx_api.h"
/* Define constants for the NAND flash simulation. */
#define TOTAL_BLOCKS 8
#define PHYSICAL_PAGES_PER_BLOCK 16 /* Min value of 2 */
#define BYTES_PER_PHYSICAL_PAGE 2048 /* 2048 bytes per page */
#define WORDS_PER_PHYSICAL_PAGE 2048/4 /* Words per page */
#define SPARE_BYTES_PER_PAGE 64 /* 64 "spare" bytes per page */
/* For 2048 byte block spare area: */
#define BAD_BLOCK_POSITION 0 /* 0 is the bad block byte postion */
#define EXTRA_BYTE_POSITION 2 /* 2 is the extra bytes starting byte postion */
#define ECC_BYTE_POSITION 40 /* 40 is the ECC starting byte position */
/* Definition of the spare area is relative to the block size of the NAND part and perhaps manufactures of the NAND part.
Here are some common definitions:
256 Byte Block
Bytes Meaning
0,1,2 ECC bytes
3,4,6,7 Extra
5 Bad block flag
512 Byte Block
Bytes Meaning
0,1,2,3,6,7 ECC bytes
8-15 Extra
5 Bad block flag
2048 Byte Block
Bytes Meaning
0 Bad block flag
2-39 Extra
40-63 ECC bytes
*/
typedef struct PHYSICAL_PAGE_STRUCT
{
unsigned long memory[WORDS_PER_PHYSICAL_PAGE];
unsigned char spare[SPARE_BYTES_PER_PAGE];
} PHYSICAL_PAGE;
typedef struct NAND_BLOCK_DIAG_STRUCT
{
unsigned long erases;
unsigned long page_writes[PHYSICAL_PAGES_PER_BLOCK];
unsigned long max_page_writes[PHYSICAL_PAGES_PER_BLOCK];
} NAND_BLOCK_DIAG;
typedef struct NAND_FLASH_BLOCK_STRUCT
{
PHYSICAL_PAGE physical_pages[PHYSICAL_PAGES_PER_BLOCK];
} NAND_FLASH_BLOCK;
NAND_FLASH_BLOCK nand_memory_area[TOTAL_BLOCKS];
NAND_BLOCK_DIAG nand_block_diag[TOTAL_BLOCKS];
/* Define NAND flash buffer for LevelX. */
ULONG nand_flash_simulator_buffer[WORDS_PER_PHYSICAL_PAGE];
ULONG *nand_flash_memory;
UINT _lx_nand_flash_simulator_initialize(LX_NAND_FLASH *nand_flash);
UINT _lx_nand_flash_simulator_read(ULONG block, ULONG page, ULONG *destination, ULONG words);
UINT _lx_nand_flash_simulator_write(ULONG block, ULONG page, ULONG *source, ULONG words);
UINT _lx_nand_flash_simulator_block_erase(ULONG block, ULONG erase_count);
UINT _lx_nand_flash_simulator_block_erased_verify(ULONG block);
UINT _lx_nand_flash_simulator_page_erased_verify(ULONG block, ULONG page);
UINT _lx_nand_flash_simulator_erase_all(VOID);
UINT _lx_nand_flash_simulator_block_status_get(ULONG block, UCHAR *bad_block_byte);
UINT _lx_nand_flash_simulator_block_status_set(ULONG block, UCHAR bad_block_byte);
UINT _lx_nand_flash_simulator_extra_bytes_get(ULONG block, ULONG page, UCHAR *destination, UINT size);
UINT _lx_nand_flash_simulator_extra_bytes_set(ULONG block, ULONG page, UCHAR *source, UINT size);
UINT _lx_nand_flash_simulator_system_error(UINT error_code, ULONG block, ULONG page);
UINT _lx_nand_flash_simulator_initialize(LX_NAND_FLASH *nand_flash)
{
/* Setup the buffer pointer. */
nand_flash_memory = (ULONG *) &nand_memory_area[0];
/* Setup geometry of the NAND flash. */
nand_flash -> lx_nand_flash_total_blocks = TOTAL_BLOCKS;
nand_flash -> lx_nand_flash_pages_per_block = PHYSICAL_PAGES_PER_BLOCK;
nand_flash -> lx_nand_flash_bytes_per_page = BYTES_PER_PHYSICAL_PAGE;
/* Setup function pointers for the NAND flash services. */
nand_flash -> lx_nand_flash_driver_read = _lx_nand_flash_simulator_read;
nand_flash -> lx_nand_flash_driver_write = _lx_nand_flash_simulator_write;
nand_flash -> lx_nand_flash_driver_block_erase = _lx_nand_flash_simulator_block_erase;
nand_flash -> lx_nand_flash_driver_block_erased_verify = _lx_nand_flash_simulator_block_erased_verify;
nand_flash -> lx_nand_flash_driver_page_erased_verify = _lx_nand_flash_simulator_page_erased_verify;
nand_flash -> lx_nand_flash_driver_block_status_get = _lx_nand_flash_simulator_block_status_get;
nand_flash -> lx_nand_flash_driver_block_status_set = _lx_nand_flash_simulator_block_status_set;
nand_flash -> lx_nand_flash_driver_extra_bytes_get = _lx_nand_flash_simulator_extra_bytes_get;
nand_flash -> lx_nand_flash_driver_extra_bytes_set = _lx_nand_flash_simulator_extra_bytes_set;
nand_flash -> lx_nand_flash_driver_system_error = _lx_nand_flash_simulator_system_error;
/* Setup local buffer for NAND flash operation. This buffer must be the page size of the NAND flash memory. */
nand_flash -> lx_nand_flash_page_buffer = &nand_flash_simulator_buffer[0];
/* Return success. */
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_read(ULONG block, ULONG page, ULONG *destination, ULONG words)
{
ULONG *flash_address;
/* Pickup the flash address. */
flash_address = &(nand_memory_area[block].physical_pages[page].memory[0]);
/* Loop to read flash. */
while (words--)
{
/* Copy word. */
*destination++ = *flash_address++;
}
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_write(ULONG block, ULONG page, ULONG *source, ULONG words)
{
ULONG *flash_address;
/* Increment the diag info. */
nand_block_diag[block].page_writes[page]++;
if (nand_block_diag[block].page_writes[page] > nand_block_diag[block].max_page_writes[page])
nand_block_diag[block].max_page_writes[page] = nand_block_diag[block].page_writes[page];
/* Pickup the flash address. */
flash_address = &(nand_memory_area[block].physical_pages[page].memory[0]);
/* Loop to write flash. */
while (words--)
{
/* Can the word be written? We can clear new bits, but just can't unclear
in a NAND device. */
if ((*source & *flash_address) != *source)
return(LX_INVALID_WRITE);
/* Copy word. */
*flash_address++ = *source++;
}
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_block_erase(ULONG block, ULONG erase_count)
{
ULONG *pointer;
ULONG words;
UINT i;
LX_PARAMETER_NOT_USED(erase_count);
/* Increment the diag info. */
nand_block_diag[block].erases++;
for (i = 0; i < PHYSICAL_PAGES_PER_BLOCK;i++)
nand_block_diag[block].page_writes[i] = 0;
/* Setup pointer. */
pointer = (ULONG *) &nand_memory_area[block];
/* Loop to erase block. */
words = sizeof(NAND_FLASH_BLOCK)/sizeof(ULONG);
while (words--)
{
/* Erase word of block. */
*pointer++ = (ULONG) 0xFFFFFFFF;
}
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_erase_all(VOID)
{
ULONG *pointer;
ULONG words;
UINT i, j;
/* Increment the diag info. */
for (i = 0; i < TOTAL_BLOCKS; i++)
{
nand_block_diag[i].erases = 0;
for (j = 0; j < PHYSICAL_PAGES_PER_BLOCK;j++)
nand_block_diag[i].page_writes[j] = 0;
}
/* Setup pointer. */
pointer = (ULONG *) &nand_memory_area[0];
/* Loop to erase block. */
words = sizeof(nand_memory_area)/sizeof(ULONG);
while (words--)
{
/* Erase word of block. */
*pointer++ = (ULONG) 0xFFFFFFFF;
}
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_block_erased_verify(ULONG block)
{
ULONG *word_ptr;
ULONG words;
/* Determine if the block is completely erased. */
/* Pickup the pointer to the first word of the block. */
word_ptr = (ULONG *) &nand_memory_area[block];
/* Calculate the number of words in a block. */
words = sizeof(NAND_FLASH_BLOCK)/sizeof(ULONG);
/* Loop to check if the block is erased. */
while (words--)
{
/* Is this word erased? */
if (*word_ptr++ != 0xFFFFFFFF)
return(LX_ERROR);
}
/* Return success. */
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_page_erased_verify(ULONG block, ULONG page)
{
ULONG *word_ptr;
ULONG words;
/* Determine if the block is completely erased. */
/* Pickup the pointer to the first word of the block's page. */
word_ptr = (ULONG *) &nand_memory_area[block].physical_pages[page];
/* Calculate the number of words in a block. */
words = WORDS_PER_PHYSICAL_PAGE;
/* Loop to check if the page is erased. */
while (words--)
{
/* Is this word erased? */
if (*word_ptr++ != 0xFFFFFFFF)
return(LX_ERROR);
}
/* Return success. */
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_block_status_get(ULONG block, UCHAR *bad_block_byte)
{
/* Pickup the bad block byte and return it. */
*bad_block_byte = nand_memory_area[block].physical_pages[0].spare[BAD_BLOCK_POSITION];
/* Return success. */
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_block_status_set(ULONG block, UCHAR bad_block_byte)
{
/* Set the bad block byte. */
nand_memory_area[block].physical_pages[0].spare[BAD_BLOCK_POSITION] = bad_block_byte;
/* Return success. */
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_extra_bytes_get(ULONG block, ULONG page, UCHAR *destination, UINT size)
{
UCHAR *source;
/* Setup source pointer in the spare area. */
source = (UCHAR *) &(nand_memory_area[block].physical_pages[page].spare[EXTRA_BYTE_POSITION]);
/* Loop to return the extra bytes requested. */
while (size--)
{
/* Retrieve an extra byte from the spare area. */
*destination++ = *source++;
}
/* Return success. */
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_extra_bytes_set(ULONG block, ULONG page, UCHAR *source, UINT size)
{
UCHAR *destination;
/* Increment the diag info. */
nand_block_diag[block].page_writes[page]++;
if (nand_block_diag[block].page_writes[page] > nand_block_diag[block].max_page_writes[page])
nand_block_diag[block].max_page_writes[page] = nand_block_diag[block].page_writes[page];
/* Setup destination pointer in the spare area. */
destination = (UCHAR *) &(nand_memory_area[block].physical_pages[page].spare[EXTRA_BYTE_POSITION]);
/* Loop to set the extra bytes. */
while (size--)
{
/* Set an extra byte in the spare area. */
*destination++ = *source++;
}
/* Return success. */
return(LX_SUCCESS);
}
UINT _lx_nand_flash_simulator_system_error(UINT error_code, ULONG block, ULONG page)
{
LX_PARAMETER_NOT_USED(error_code);
LX_PARAMETER_NOT_USED(block);
LX_PARAMETER_NOT_USED(page);
/* Custom processing goes here... all errors except for LX_NAND_ERROR_CORRECTED are fatal. */
return(LX_ERROR);
}
+107
View File
@@ -0,0 +1,107 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NAND Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nand_flash_system_error PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function handles system errors in the NAND flash. */
/* */
/* INPUT */
/* */
/* nand_flash NAND flash instance */
/* error_code System error code */
/* block Block where error occurred */
/* page Page where error occurred */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* (lx_nand_flash_driver_system_error) Driver system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
VOID _lx_nand_flash_system_error(LX_NAND_FLASH *nand_flash, UINT error_code, ULONG block, ULONG page)
{
/* Increment the system error counter. */
nand_flash -> lx_nand_flash_diagnostic_system_errors++;
/* Save the most recent system error code. */
nand_flash -> lx_nand_flash_diagnostic_system_error = error_code;
/* Determine if the system error is a NAND page corrected error. */
if (error_code == LX_NAND_ERROR_CORRECTED)
{
/* Yes, increment error correction information. */
nand_flash -> lx_nand_flash_page_corrections++;
/* Remember the last block/page of corrected error. */
nand_flash -> lx_nand_flash_last_block_correction = block;
nand_flash -> lx_nand_flash_last_page_correction = page;
}
/* Determine if the driver has setup a system error handler. */
if (nand_flash -> lx_nand_flash_driver_system_error)
{
/* Yes, call the driver's system error handler. */
(nand_flash -> lx_nand_flash_driver_system_error)(error_code, block, page);
}
}
+562
View File
@@ -0,0 +1,562 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_block_reclaim PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reclaims one block from the NOR flash. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nor_flash_driver_block_erase Driver erase block */
/* _lx_nor_flash_driver_write Driver flash sector write */
/* _lx_nor_flash_driver_read Driver flash sector read */
/* _lx_nor_flash_next_block_to_erase_find */
/* Find next block to erase */
/* _lx_nor_flash_physical_sector_allocate */
/* Allocate new logical sector */
/* _lx_nor_flash_sector_mapping_cache_invalidate */
/* Invalidate cache entry */
/* _lx_nor_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_block_reclaim(LX_NOR_FLASH *nor_flash)
{
ULONG *block_word_ptr;
ULONG *list_word_ptr;
ULONG list_word;
ULONG i;
ULONG erase_block;
ULONG erase_count;
ULONG temp_erase_count;
ULONG erase_started_value;
ULONG mapped_sectors;
ULONG obsolete_sectors;
ULONG free_sectors;
ULONG logical_sector;
ULONG *new_mapping_address;
ULONG *new_sector_address;
ULONG new_mapping_entry;
UINT status;
/* Determine the next block to erase. */
_lx_nor_flash_next_block_to_erase_find(nor_flash, &erase_block, &erase_count, &mapped_sectors, &obsolete_sectors);
/* Determine if the search pointer is set for this block. */
if (nor_flash -> lx_nor_flash_free_block_search == erase_block)
{
/* Ensure the search block is not the block we are trying to free. */
nor_flash -> lx_nor_flash_free_block_search = erase_block + 1;
/* Check for wrap condition. */
if (nor_flash -> lx_nor_flash_free_block_search >= nor_flash -> lx_nor_flash_total_blocks)
nor_flash -> lx_nor_flash_free_block_search = 0;
}
/* Setup the block word pointer to the first word of the search block. */
block_word_ptr = nor_flash -> lx_nor_flash_base_address + (nor_flash -> lx_nor_flash_words_per_block * erase_block);
/* Determine if this block is completely obsolete. */
if (obsolete_sectors == nor_flash -> lx_nor_flash_physical_sectors_per_block)
{
/* Write the erased started indication. */
erase_started_value = LX_BLOCK_ERASE_STARTED;
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &erase_started_value, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Erase the entire block. */
status = _lx_nor_flash_driver_block_erase(nor_flash, erase_block, erase_count+1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Increment the erase count. */
erase_count++;
/* Determine if the new erase count exceeds the maximum. */
if (erase_count > ((ULONG) LX_BLOCK_ERASE_COUNT_MAX))
{
/* Yes, erase count is in overflow. Stay at the maximum count. */
erase_count = ((ULONG) LX_BLOCK_ERASE_COUNT_MAX);
}
/* Determine if we need to update the maximum erase count. */
if (erase_count > nor_flash -> lx_nor_flash_maximum_erase_count)
{
/* Yes, a new maximum is present. */
nor_flash -> lx_nor_flash_maximum_erase_count = erase_count;
}
/* Setup the free bit map that corresponds to the free physical sectors in this
block. Note that we only need to setup the portion of the free bit map that doesn't
have sectors associated with it. */
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (nor_flash -> lx_nor_flash_block_bit_map_words - 1)),
&(nor_flash -> lx_nor_flash_block_bit_map_mask), 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Write the initial erase count for the block with upper bit set. */
temp_erase_count = (erase_count | LX_BLOCK_ERASED);
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &temp_erase_count, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Write the final initial erase count for the block. */
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &erase_count, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Update parameters of this flash. */
nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + obsolete_sectors;
nor_flash -> lx_nor_flash_obsolete_physical_sectors = nor_flash -> lx_nor_flash_obsolete_physical_sectors - obsolete_sectors;
}
else
{
/* Calculate the number of free sectors in this block. */
free_sectors = nor_flash -> lx_nor_flash_physical_sectors_per_block - (obsolete_sectors + mapped_sectors);
/* Determine if there are enough free sectors outside of this block to reclaim this block. */
if (mapped_sectors <= (nor_flash -> lx_nor_flash_free_physical_sectors - free_sectors))
{
/* Setup a pointer to the mapped list. */
list_word_ptr = block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset;
/* Now search through the list to find mapped sectors to move. */
for (i = 0; i < nor_flash -> lx_nor_flash_physical_sectors_per_block; i++)
{
/* Pickup the mapped sector list entry. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
list_word = *(list_word_ptr);
#else
status = _lx_nor_flash_driver_read(nor_flash, list_word_ptr, &list_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Determine if the entry hasn't been used. */
if (list_word == LX_NOR_PHYSICAL_SECTOR_FREE)
{
/* Since allocations are done sequentially in the block, we know nothing
else exists after this point. */
break;
}
/* Is this entry mapped? */
if (list_word & LX_NOR_PHYSICAL_SECTOR_VALID)
{
/* Pickup the logical sector associated with this mapped physical sector. */
logical_sector = list_word & LX_NOR_LOGICAL_SECTOR_MASK;
/* Invalidate the old sector mapping cache entry. */
_lx_nor_flash_sector_mapping_cache_invalidate(nor_flash, logical_sector);
/* Allocate a new physical sector for this write. */
_lx_nor_flash_physical_sector_allocate(nor_flash, logical_sector, &new_mapping_address, &new_sector_address);
/* Check to see if the new sector is also in the erase block. */
if ((new_sector_address >= block_word_ptr) && (new_sector_address < (block_word_ptr + nor_flash -> lx_nor_flash_words_per_block)))
{
/* Yes, the new sector was found in the block to be erased. Simply move the search pointer
to the block after the erase block and search for another sector from there. */
nor_flash -> lx_nor_flash_free_block_search = erase_block + 1;
/* Check for wrap condition. */
if (nor_flash -> lx_nor_flash_free_block_search >= nor_flash -> lx_nor_flash_total_blocks)
nor_flash -> lx_nor_flash_free_block_search = 0;
/* Allocate a new physical sector for this write. */
_lx_nor_flash_physical_sector_allocate(nor_flash, logical_sector, &new_mapping_address, &new_sector_address);
/* Check again for the new sector inside of the block to erase. This should be impossible, since
we check previously if there are enough free sectors outside of this block needed to reclaim
this block. */
if ((new_sector_address >= block_word_ptr) && (new_sector_address < (block_word_ptr + LX_NOR_SECTOR_SIZE)))
{
/* System error, a new sector is not available outside of the erase block.
Clear the new sector so we fall through to the error handling. */
new_mapping_address = LX_NULL;
}
}
/* Determine if the new sector allocation was successful. */
if (new_mapping_address)
{
/* Yes, we were able to allocate a new physical sector. */
#ifdef LX_DIRECT_READ
/* First, write the sector data to the new physical sector. */
status = _lx_nor_flash_driver_write(nor_flash, new_sector_address, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_offset) +
(i * LX_NOR_SECTOR_SIZE), LX_NOR_SECTOR_SIZE);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#else
/* First, read the sector data into the internal memory of the NOR flash instance. This internal memory
is supplied by the underlying driver during initialization. */
status = _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_offset) +
(i * LX_NOR_SECTOR_SIZE), nor_flash -> lx_nor_flash_sector_buffer,
LX_NOR_SECTOR_SIZE);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Next, write the sector data from the internal buffer to the new physical sector. */
status = _lx_nor_flash_driver_write(nor_flash, new_sector_address, nor_flash -> lx_nor_flash_sector_buffer, LX_NOR_SECTOR_SIZE);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Now deprecate the old sector mapping. */
/* Clear bit 30, which indicates this sector is superceded. */
list_word = list_word & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED);
/* Write the value back to the flash to clear bit 30. */
status = _lx_nor_flash_driver_write(nor_flash, list_word_ptr, &list_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Now build the new mapping entry - with the not valid bit set initially. */
new_mapping_entry = ((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) | (ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID | logical_sector;
/* Write out the new mapping entry. */
status = _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Now clear the not valid bit to make this sector mapping valid. This is done because the writing of the extra bytes itself can
be interrupted and we need to make sure this can be detected when the flash is opened again. */
new_mapping_entry = new_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID);
/* Clear the not valid bit. */
status = _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Now clear bit 31, which indicates this sector is now obsoleted. */
list_word = list_word & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
/* Write the value back to the flash to clear bit 31. */
status = _lx_nor_flash_driver_write(nor_flash, list_word_ptr, &list_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
}
else
{
/* Call system error handler - the allocation should always succeed at this point. */
_lx_nor_flash_system_error(nor_flash, LX_SYSTEM_ALLOCATION_FAILED);
/* Return the error. */
return(status);
}
/* Decrement the number of mapped sectors. */
mapped_sectors--;
/* Determine if we are done. */
if (mapped_sectors == 0)
break;
}
/* Move the list pointer ahead. */
list_word_ptr++;
}
/* Write the erased started indication. */
erase_started_value = LX_BLOCK_ERASE_STARTED;
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &erase_started_value, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Erase the entire block. */
status = _lx_nor_flash_driver_block_erase(nor_flash, erase_block, erase_count+1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Increment the erase count. */
erase_count++;
/* Determine if the new erase count exceeds the maximum. */
if (erase_count > ((ULONG) LX_BLOCK_ERASE_COUNT_MAX))
{
/* Yes, erase count is in overflow. Stay at the maximum count. */
erase_count = ((ULONG) LX_BLOCK_ERASE_COUNT_MAX);
}
/* Determine if we need to update the maximum erase count. */
if (erase_count > nor_flash -> lx_nor_flash_maximum_erase_count)
{
/* Yes, a new maximum is present. */
nor_flash -> lx_nor_flash_maximum_erase_count = erase_count;
}
/* Setup the free bit map that corresponds to the free physical sectors in this
block. Note that we only need to setup the portion of the free bit map that doesn't
have sectors associated with it. */
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (nor_flash -> lx_nor_flash_block_bit_map_words - 1)) ,
&(nor_flash -> lx_nor_flash_block_bit_map_mask), 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Write the initial erase count for the block with the upper bit set. */
temp_erase_count = (erase_count | LX_BLOCK_ERASED);
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &temp_erase_count, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Write the final initial erase count for the block. */
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &erase_count, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Update parameters of this flash. */
nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + obsolete_sectors;
nor_flash -> lx_nor_flash_obsolete_physical_sectors = nor_flash -> lx_nor_flash_obsolete_physical_sectors - obsolete_sectors;
}
}
/* Return status. */
return(LX_SUCCESS);
}
+129
View File
@@ -0,0 +1,129 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_close PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function closes a NOR flash instance. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* tx_mutex_delete Delete thread-safe mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_close(LX_NOR_FLASH *nor_flash)
{
TX_INTERRUPT_SAVE_AREA
/* Lockout interrupts for NOR flash close. */
TX_DISABLE
/* See if the media is the only one on the media opened list. */
if ((_lx_nor_flash_opened_ptr == nor_flash) &&
(_lx_nor_flash_opened_ptr == nor_flash -> lx_nor_flash_open_next) &&
(_lx_nor_flash_opened_ptr == nor_flash -> lx_nor_flash_open_previous))
{
/* Only opened NOR flash, just set the opened list to NULL. */
_lx_nor_flash_opened_ptr = LX_NULL;
}
else
{
/* Otherwise, not the only opened NOR flash, link-up the neighbors. */
(nor_flash -> lx_nor_flash_open_next) -> lx_nor_flash_open_previous =
nor_flash -> lx_nor_flash_open_previous;
(nor_flash -> lx_nor_flash_open_previous) -> lx_nor_flash_open_next =
nor_flash -> lx_nor_flash_open_next;
/* See if we have to update the opened list head pointer. */
if (_lx_nor_flash_opened_ptr == nor_flash)
{
/* Yes, move the head pointer to the next opened NOR flash. */
_lx_nor_flash_opened_ptr = nor_flash -> lx_nor_flash_open_next;
}
}
/* Decrement the opened NOR flash counter. */
_lx_nor_flash_opened_count--;
/* Finally, indicate that this NOR flash is closed. */
nor_flash -> lx_nor_flash_state = LX_NOR_FLASH_CLOSED;
/* Restore interrupt posture. */
TX_RESTORE
#ifdef LX_THREAD_SAFE_ENABLE
/* Delete the thread safe mutex. */
tx_mutex_delete(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return success. */
return(LX_SUCCESS);
}
+112
View File
@@ -0,0 +1,112 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_defragment PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function defragments the NOR flash. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nor_flash_block_reclaim Reclaim a NOR flash block */
/* tx_mutex_get Get thread protection */
/* tx_mutex_put Release thread protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_defragment(LX_NOR_FLASH *nor_flash)
{
ULONG i;
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Loop for max number of blocks, while there are obsolete count. */
for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
{
/* Determine if there is any more defragment work. */
if (nor_flash -> lx_nor_flash_obsolete_physical_sectors == 0)
break;
/* Call the block reclaim function to defragment. */
_lx_nor_flash_block_reclaim(nor_flash);
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return successful completion. */
return(LX_SUCCESS);
}
@@ -0,0 +1,123 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_driver_block_erase PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs a NOR flash block erase. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* block Block number to erase */
/* erase_count Erase count for this block */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* (lx_nor_flash_driver_block_erase) Actual driver block erase */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_driver_block_erase(LX_NOR_FLASH *nor_flash, ULONG block, ULONG erase_count)
{
UINT status;
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
UINT i;
ULONG *block_start_address;
ULONG *block_end_address;
ULONG *cache_entry_start;
ULONG *cache_entry_end;
/* Calculate the block starting address. */
block_start_address = nor_flash -> lx_nor_flash_base_address + (block * nor_flash -> lx_nor_flash_words_per_block);
block_end_address = block_start_address + nor_flash -> lx_nor_flash_words_per_block;
/* Loop through the cache entries to see if there is a sector in cache. */
for (i = 0; i < nor_flash -> lx_nor_flash_extended_cache_entries; i++)
{
/* Search through the cache to see if this cache entry needs to be invalidated. */
/* Determine the cache entry addresses. */
cache_entry_start = nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address;
cache_entry_end = cache_entry_start + LX_NOR_SECTOR_SIZE;
/* Determine if the flash address in in the cache entry. */
if ((cache_entry_start) && (block_start_address <= cache_entry_start) && (block_end_address > cache_entry_end))
{
/* Yes, this cache entry is in the block to be erased so invalidate it. */
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address = LX_NULL;
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count = 0;
}
}
#endif
/* Call the actual driver block erase function. */
status = (nor_flash -> lx_nor_flash_driver_block_erase)(block, erase_count);
/* Return completion status. */
return(status);
}
+207
View File
@@ -0,0 +1,207 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_extended_cache_read PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs a read of the NOR flash memory. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* flash_address Address of NOR flash to read */
/* destination Destination for the read */
/* words Number of words to read */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* (lx_nor_flash_driver_read) Actual driver read */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_driver_read(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *destination, ULONG words)
{
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
UINT status;
UINT i;
ULONG *cache_entry_start;
ULONG *cache_entry_end;
ULONG cache_offset;
UINT least_used_cache_entry;
/* Is the request a whole sector or a partial sector. */
if ((words == 1) && (nor_flash -> lx_nor_flash_extended_cache_entries))
{
/* One word request, which implies that it is a NOR flash metadata read. */
/* Initialize the least used cache entry. */
least_used_cache_entry = 0;
do
{
/* Loop through the cache entries to see if there is a sector in cache. */
for (i = 0; i < nor_flash -> lx_nor_flash_extended_cache_entries; i++)
{
/* Search through the cache to find the entry. */
/* Determine the cache entry addresses. */
cache_entry_start = nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address;
cache_entry_end = cache_entry_start + LX_NOR_SECTOR_SIZE;
/* Determine if the flash address in in the cache entry. */
if ((cache_entry_start) && (flash_address >= cache_entry_start) && (flash_address < cache_entry_end))
{
/* Yes, we found the entry. */
/* Increment the accessed count. */
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count++;
/* Calculate the offset into the cache entry. */
cache_offset = (ULONG)(flash_address - cache_entry_start);
/* Copy the word from the cache. */
*destination = *(nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory + cache_offset);
/* Increment the number of cache hits. */
nor_flash -> lx_nor_flash_extended_cache_hits++;
/* Return success. */
return(LX_SUCCESS);
}
else
{
/* Determine if we have a new least used sector. */
if (i != least_used_cache_entry)
{
/* Determine if this entry has a smaller accessed count. */
if (nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count <
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_access_count)
{
/* New least used entry. */
least_used_cache_entry = i;
}
}
}
}
/* Now read in the sector into the cache. */
cache_offset = (ULONG)(flash_address - nor_flash -> lx_nor_flash_base_address);
cache_offset = cache_offset & ~((ULONG) (LX_NOR_SECTOR_SIZE-1));
cache_entry_start = nor_flash -> lx_nor_flash_base_address + cache_offset;
/* Call the actual driver read function. */
status = (nor_flash -> lx_nor_flash_driver_read)(cache_entry_start,
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_sector_memory,
LX_NOR_SECTOR_SIZE);
/* Determine if there was an error. */
if (status != LX_SUCCESS)
{
/* Return the error to the caller. */
return(status);
}
/* Setup the cache entry. */
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_sector_address = cache_entry_start;
nor_flash -> lx_nor_flash_extended_cache[least_used_cache_entry].lx_nor_flash_extended_cache_entry_access_count = 0;
/* Increment the number of cache misses. */
nor_flash -> lx_nor_flash_extended_cache_misses++;
/* Decrement the number of cache hits, so that the increment that will happen next will be cancelled out. */
nor_flash -> lx_nor_flash_extended_cache_hits--;
} while (status == LX_SUCCESS);
/* Return success. */
return(LX_SUCCESS);
}
else
{
/* Call the actual driver read function. */
status = (nor_flash -> lx_nor_flash_driver_read)(flash_address, destination, words);
/* Return completion status. */
return(status);
}
#else
UINT status;
/* Call the actual driver read function. */
status = (nor_flash -> lx_nor_flash_driver_read)(flash_address, destination, words);
/* Return completion status. */
return(status);
#endif
}
+141
View File
@@ -0,0 +1,141 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_driver_write PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs a write of the NOR flash memory. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* flash_address Address of NOR flash to write */
/* source Source for the write */
/* words Number of words to write */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* (lx_nor_flash_driver_write) Actual driver write */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_driver_write(LX_NOR_FLASH *nor_flash, ULONG *flash_address, ULONG *source, ULONG words)
{
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
UINT status;
UINT i;
ULONG *cache_entry_start;
ULONG *cache_entry_end;
ULONG cache_offset;
/* Is the request a whole sector or a partial sector. */
if ((words == 1) && (nor_flash -> lx_nor_flash_extended_cache_entries))
{
/* One word request, which implies that it is a NOR flash metadata write. */
/* Loop through the cache entries to see if there is a sector in cache. */
for (i = 0; i < nor_flash -> lx_nor_flash_extended_cache_entries; i++)
{
/* Search through the cache to see if there is a cache entry. */
/* Determine the cache entry addresses. */
cache_entry_start = nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address;
cache_entry_end = cache_entry_start + LX_NOR_SECTOR_SIZE;
/* Determine if the flash address in in the cache entry. */
if ((cache_entry_start) && (flash_address >= cache_entry_start) && (flash_address < cache_entry_end))
{
/* Yes, we found the entry. */
/* Calculate the offset into the cache entry. */
cache_offset = (ULONG)(flash_address - cache_entry_start);
/* Copy the word into the cache. */
*(nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory + cache_offset) = *source;
/* Get out of the loop. */
break;
}
}
}
/* In any case, call the actual driver write function. */
status = (nor_flash -> lx_nor_flash_driver_write)(flash_address, source, words);
/* Return completion status. */
return(status);
#else
UINT status;
/* Call the actual driver write function. */
status = (nor_flash -> lx_nor_flash_driver_write)(flash_address, source, words);
/* Return completion status. */
return(status);
#endif
}
@@ -0,0 +1,147 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_extended_cache_enable PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function enables or disables the extended cache. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* memory Address of RAM for cache */
/* size Size of the RAM for cache */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_extended_cache_enable(LX_NOR_FLASH *nor_flash, VOID *memory, ULONG size)
{
#ifndef LX_NOR_DISABLE_EXTENDED_CACHE
UINT i;
ULONG cache_size;
ULONG *cache_memory;
/* Determine if memory was specified but with an invalid size (less than one NOR sector). */
if ((memory) && (size < LX_NOR_SECTOR_SIZE))
{
/* Error in memory size supplied. */
return(LX_ERROR);
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Initialize the internal NOR cache. */
nor_flash -> lx_nor_flash_extended_cache_entries = 0;
/* Calculate cache size in words. */
cache_size = size/sizeof(ULONG);
/* Setup cache memory pointer. */
cache_memory = (ULONG *) memory;
/* Loop through the memory supplied and assign to cache entries. */
i = 0;
while (cache_size >= LX_NOR_SECTOR_SIZE)
{
/* Setup this cache entry. */
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_address = LX_NULL;
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_sector_memory = cache_memory;
nor_flash -> lx_nor_flash_extended_cache[i].lx_nor_flash_extended_cache_entry_access_count = 0;
/* Move the cache memory forward. */
cache_memory = cache_memory + LX_NOR_SECTOR_SIZE;
/* Decrement the size. */
cache_size = cache_size - LX_NOR_SECTOR_SIZE;
/* Move to next cache entry. */
i++;
}
/* Save the number of cache entries. */
nor_flash -> lx_nor_flash_extended_cache_entries = i;
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return successful completion. */
return(LX_SUCCESS);
#else
/* Return disabled error message. */
return(LX_DISABLED);
#endif
}
+84
View File
@@ -0,0 +1,84 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Include necessary system files. */
#include "lx_api.h"
/* Define the NOR flash opened list head and opened count. */
LX_NOR_FLASH *_lx_nor_flash_opened_ptr;
ULONG _lx_nor_flash_opened_count;
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_initialize PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function initializes the NOR flash data structures. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_initialize(void)
{
/* Clear open list head pointer and opened count. */
_lx_nor_flash_opened_ptr = LX_NULL;
_lx_nor_flash_opened_count = 0;
/* Return success! */
return(LX_SUCCESS);
}
@@ -0,0 +1,475 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_logical_sector_find PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function attempts to find the specified logical sector in */
/* the NOR flash. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* logical_sector Logical sector number */
/* superceded_check Check for sector being */
/* superceded (can happen if */
/* on interruptions of sector */
/* write) */
/* physical_sector_map_entry Destination for physical */
/* sector map entry address */
/* physical_sector_address Destination for physical */
/* sector data */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nor_flash_driver_read Driver flash sector read */
/* _lx_nor_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_logical_sector_find(LX_NOR_FLASH *nor_flash, ULONG logical_sector, ULONG superceded_check, ULONG **physical_sector_map_entry, ULONG **physical_sector_address)
{
ULONG *block_word_ptr;
ULONG *list_word_ptr;
ULONG list_word;
ULONG min_logical_sector;
ULONG max_logical_sector;
ULONG mapped_sectors;
ULONG total_blocks;
ULONG total_sectors;
ULONG i, j;
ULONG search_start;
LX_NOR_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr = LX_NULL;
LX_NOR_SECTOR_MAPPING_CACHE_ENTRY temp_sector_mapping_cache_entry;
#ifndef LX_DIRECT_READ
UINT status;
#endif
/* Initialize the return parameters. */
*physical_sector_map_entry = (ULONG *) 0;
*physical_sector_address = (ULONG *) 0;
/* Determine if there are any mapped physical sectors. */
if (nor_flash -> lx_nor_flash_mapped_physical_sectors == 0)
{
/* No mapped sector so nothing can be found!. */
return(LX_SECTOR_NOT_FOUND);
}
/* Determine if the sector mapping cache is enabled. */
if (nor_flash -> lx_nor_flash_sector_mapping_cache_enabled)
{
/* Calculate the starting index of the sector cache for this sector entry. */
i = (logical_sector & LX_NOR_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NOR_SECTOR_MAPPING_CACHE_DEPTH;
/* Build a pointer to the cache entry. */
sector_mapping_cache_entry_ptr = &nor_flash -> lx_nor_flash_sector_mapping_cache[i];
/* Determine if the sector is in the sector mapping cache - assuming the depth of the sector
mapping cache is LX_NOR_SECTOR_MAPPING_CACHE_DEPTH entries. */
if ((sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_logical_sector) == (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Increment the sector mapping cache hit counter. */
nor_flash -> lx_nor_flash_sector_mapping_cache_hits++;
/* Yes, return the cached values associated with the sector. */
*physical_sector_map_entry = sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_map_entry;
*physical_sector_address = sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_address;
/* Don't move anything since we found the entry at the top. */
/* Return a successful status. */
return(LX_SUCCESS);
}
else if (((sector_mapping_cache_entry_ptr + 1) -> lx_nor_sector_mapping_cache_logical_sector) == (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Increment the sector mapping cache hit counter. */
nor_flash -> lx_nor_flash_sector_mapping_cache_hits++;
/* Yes, return the cached values associated with the sector. */
*physical_sector_map_entry = (sector_mapping_cache_entry_ptr + 1) -> lx_nor_sector_mapping_cache_physical_sector_map_entry;
*physical_sector_address = (sector_mapping_cache_entry_ptr + 1) -> lx_nor_sector_mapping_cache_physical_sector_address;
/* Just swap the first and second entry. */
temp_sector_mapping_cache_entry = *(sector_mapping_cache_entry_ptr);
*(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = temp_sector_mapping_cache_entry;
/* Return a successful status. */
return(LX_SUCCESS);
}
else if (((sector_mapping_cache_entry_ptr + 2) -> lx_nor_sector_mapping_cache_logical_sector) == (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Increment the sector mapping cache hit counter. */
nor_flash -> lx_nor_flash_sector_mapping_cache_hits++;
/* Yes, return the cached value. */
*physical_sector_map_entry = (sector_mapping_cache_entry_ptr + 2) -> lx_nor_sector_mapping_cache_physical_sector_map_entry;
*physical_sector_address = (sector_mapping_cache_entry_ptr + 2) -> lx_nor_sector_mapping_cache_physical_sector_address;
/* Move the third entry to the top and the first two entries down. */
temp_sector_mapping_cache_entry = *(sector_mapping_cache_entry_ptr);
*(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = temp_sector_mapping_cache_entry;
/* Return a successful status. */
return(LX_SUCCESS);
}
else if (((sector_mapping_cache_entry_ptr + 3) -> lx_nor_sector_mapping_cache_logical_sector) == (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Increment the sector mapping cache hit counter. */
nor_flash -> lx_nor_flash_sector_mapping_cache_hits++;
/* Yes, return the cached value. */
*physical_sector_map_entry = (sector_mapping_cache_entry_ptr + 3) -> lx_nor_sector_mapping_cache_physical_sector_map_entry;
*physical_sector_address = (sector_mapping_cache_entry_ptr + 3) -> lx_nor_sector_mapping_cache_physical_sector_address;
/* Move the last entry to the top and the first three entries down. */
temp_sector_mapping_cache_entry = *(sector_mapping_cache_entry_ptr);
*(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 3);
*(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = temp_sector_mapping_cache_entry;
/* Return a successful status. */
return(LX_SUCCESS);
}
/* If we get here, we have a cache miss so increment the counter before we fall through the loop. */
nor_flash -> lx_nor_flash_sector_mapping_cache_misses++;
}
/* Setup the total number of mapped sectors. */
mapped_sectors = nor_flash -> lx_nor_flash_mapped_physical_sectors;
/* Start searching from the last found block. */
i = nor_flash -> lx_nor_flash_found_block_search;
/* Setup the starting sector to look at. */
j = nor_flash -> lx_nor_flash_found_sector_search;
/* Pickup the total number of blocks. */
total_blocks = nor_flash -> lx_nor_flash_total_blocks;
/* Loop through the blocks to attempt to find the mapped logical sector. */
while (total_blocks--)
{
/* Setup the block word pointer to the first word of the search block. */
block_word_ptr = (nor_flash -> lx_nor_flash_base_address + (i * nor_flash -> lx_nor_flash_words_per_block));
/* Determine if the minimum and maximum logical sector values are present in the block header. If these are
present, we can quickly skip blocks that don't have our sector. */
/* Read the minimum and maximum logical sector values in this block. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
min_logical_sector = *(block_word_ptr + LX_NOR_FLASH_MIN_LOGICAL_SECTOR_OFFSET);
#else
status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr + LX_NOR_FLASH_MIN_LOGICAL_SECTOR_OFFSET, &min_logical_sector, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
#ifdef LX_DIRECT_READ
/* Read the word directly. */
max_logical_sector = *(block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET);
#else
status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET, &max_logical_sector, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Are the values valid? */
if ((min_logical_sector != LX_ALL_ONES) && (max_logical_sector != LX_ALL_ONES))
{
/* Now let's check to see if the search sector is within this range. */
if ((logical_sector < min_logical_sector) || (logical_sector > max_logical_sector))
{
/* Move to the next block. */
i++;
/* Determine if we have wrapped. */
if (i >= nor_flash -> lx_nor_flash_total_blocks)
{
/* Yes, we have wrapped, set to block 0. */
i = 0;
}
/* Start at the first sector in the next block. */
j = 0;
/* No point in looking further into this block, just continue the loop. */
continue;
}
}
/* Setup the total number of sectors. */
total_sectors = nor_flash -> lx_nor_flash_physical_sectors_per_block;
/* Remember the start of the search. */
search_start = j;
/* Now search through the sector list to find a match. */
while (total_sectors--)
{
/* Setup a pointer to the mapped list. */
list_word_ptr = block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j;
/* Read in the mapped list for this block. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
list_word = *(list_word_ptr);
#else
status = _lx_nor_flash_driver_read(nor_flash, list_word_ptr, &list_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Determine if the entry hasn't been used. */
if (list_word == LX_NOR_PHYSICAL_SECTOR_FREE)
{
/* Since the mapping is done sequentially in the block, we know nothing
else exists after this point. */
/* Determine if the search started at the beginning of the block. */
if (search_start == 0)
{
/* Yes, we started at the beginning of the block. We are now done with this block. */
break;
}
else
{
/* Setup the new total to the search start. */
total_sectors = search_start;
/* Clear search start. */
search_start = 0;
/* Start search over. */
j = 0;
continue;
}
}
/* Is this entry valid? */
if ((list_word & (LX_NOR_PHYSICAL_SECTOR_VALID | LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID)) == LX_NOR_PHYSICAL_SECTOR_VALID)
{
/* Decrement the number of mapped sectors. */
mapped_sectors--;
/* Do we have a valid sector match? */
if ((list_word & LX_NOR_LOGICAL_SECTOR_MASK) == logical_sector)
{
/* Determine if we care about the superceded bit. */
if (superceded_check == LX_FALSE)
{
/* Prepare the return information. */
*physical_sector_map_entry = list_word_ptr;
*physical_sector_address = block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_offset + (j * LX_NOR_SECTOR_SIZE);
/* Determine if the sector mapping cache is enabled. */
if (nor_flash -> lx_nor_flash_sector_mapping_cache_enabled)
{
/* Yes, update the cache with the sector mapping. */
/* Move all the cache entries down so the oldest is at the bottom. */
*(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr);
/* Setup the new sector information in the cache. */
sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_logical_sector = (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID);
sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_map_entry = *physical_sector_map_entry;
sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_address = *physical_sector_address;
}
/* Remember the last found block for next search. */
nor_flash -> lx_nor_flash_found_block_search = i;
/* Remember the last found sector. */
nor_flash -> lx_nor_flash_found_sector_search = j+1;
/* Has this wrapped around? */
if (nor_flash -> lx_nor_flash_found_sector_search >= nor_flash -> lx_nor_flash_physical_sectors_per_block)
{
/* Reset to the beginning sector. */
nor_flash -> lx_nor_flash_found_sector_search = 0;
}
/* Return success! */
return(LX_SUCCESS);
}
/* Check for the superceded bit being clear, which means the sector was superceded. */
else if (list_word & LX_NOR_PHYSICAL_SECTOR_SUPERCEDED)
{
/* Prepare the return information. */
*physical_sector_map_entry = list_word_ptr;
*physical_sector_address = block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_offset + (j * LX_NOR_SECTOR_SIZE);
/* No need to update the cache here, since this condition only happens during initialization. */
/* Remember the last found block for next search. */
nor_flash -> lx_nor_flash_found_block_search = i;
/* Remember the last found sector. */
nor_flash -> lx_nor_flash_found_sector_search = j+1;
/* Has this wrapped around? */
if (nor_flash -> lx_nor_flash_found_sector_search >= nor_flash -> lx_nor_flash_physical_sectors_per_block)
{
/* Reset to the beginning sector. */
nor_flash -> lx_nor_flash_found_sector_search = 0;
}
/* Return success! */
return(LX_SUCCESS);
}
}
}
/* Move to the next list entry. */
j++;
/* Check for wrap around. */
if (j >= nor_flash -> lx_nor_flash_physical_sectors_per_block)
{
/* Yes, wrap around, go back to the beginning. */
j = 0;
}
}
/* Determine if there are any more mapped sectors. */
if (mapped_sectors == 0)
break;
/* Move to the next block. */
i++;
/* Determine if we have wrapped. */
if (i >= nor_flash -> lx_nor_flash_total_blocks)
{
/* Yes, we have wrapped, set to block 0. */
i = 0;
}
/* Start at the first sector in the next block. */
j = 0;
}
/* Return sector not found status. */
return(LX_SECTOR_NOT_FOUND);
}
@@ -0,0 +1,291 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_next_block_to_erase_find PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function finds the next block to erase in the NOR flash. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* return_erase_block Returned block to erase */
/* return_erase_count Returned erase count of block */
/* return_mapped_sectors Returned number of mapped */
/* sectors */
/* return_obsolete_sectors Returned number of obsolete */
/* sectors */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nor_flash_driver_read Driver flash sector read */
/* _lx_nor_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_next_block_to_erase_find(LX_NOR_FLASH *nor_flash, ULONG *return_erase_block, ULONG *return_erase_count, ULONG *return_mapped_sectors, ULONG *return_obsolete_sectors)
{
ULONG *block_word_ptr;
ULONG *list_word_ptr;
ULONG list_word;
ULONG i, j;
ULONG mapped_sectors;
ULONG erase_count;
ULONG obsolete_sectors;
ULONG min_block_erase = 0;
ULONG min_block_erase_count;
ULONG min_block_obsolete_count = 0;
ULONG min_block_mapped_count = 0;
ULONG max_obsolete_sectors;
ULONG max_obsolete_block = 0;
ULONG max_obsolete_erase_count = 0;
ULONG max_obsolete_mapped_count = 0;
ULONG min_system_block_erase_count;
ULONG max_system_block_erase_count;
ULONG erase_count_threshold;
#ifndef LX_DIRECT_READ
UINT status;
#endif
/* Setup the block word pointer to the first word of the search block. */
block_word_ptr = nor_flash -> lx_nor_flash_base_address;
/* Initialize the minimum erase count. */
min_block_erase_count = LX_ALL_ONES;
/* Initialize the system minimum and maximum erase counts. */
min_system_block_erase_count = LX_ALL_ONES;
max_system_block_erase_count = 0;
/* Initialize the maximum obsolete sector count. */
max_obsolete_sectors = 0;
/* Calculate the erase count threshold. */
if (nor_flash -> lx_nor_flash_free_physical_sectors >= nor_flash -> lx_nor_flash_physical_sectors_per_block)
{
/* Calculate erase count threshold by adding constant to the current minimum. */
erase_count_threshold = nor_flash -> lx_nor_flash_minimum_erase_count + LX_NOR_FLASH_MAX_ERASE_COUNT_DELTA;
}
else
{
/* When the number of free sectors is low, simply pick the block that has the most number of obsolete sectors. */
erase_count_threshold = LX_ALL_ONES;
}
/* Loop through the blocks to attempt to find the mapped logical sector. */
for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
{
/* Read the erase count of this block. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
erase_count = *(block_word_ptr);
#else
status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &erase_count, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Update the system minimum and maximum erase counts. */
if (erase_count < min_system_block_erase_count)
min_system_block_erase_count = erase_count;
if (erase_count > max_system_block_erase_count)
max_system_block_erase_count = erase_count;
/* Compute the number of obsolete and mapped sectors for this block. */
obsolete_sectors = 0;
mapped_sectors = 0;
/* Setup a pointer to the mapped list. */
list_word_ptr = block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset;
/* Loop through the mapped list for this block. */
for (j = 0; j < nor_flash -> lx_nor_flash_physical_sectors_per_block; j++)
{
/* Read the current mapping entry. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
list_word = *(list_word_ptr);
#else
status = _lx_nor_flash_driver_read(nor_flash, list_word_ptr, &list_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Determine if the entry hasn't been used. */
if (list_word == LX_NOR_PHYSICAL_SECTOR_FREE)
{
/* Since allocations are done sequentially in the block, we know nothing
else exists after this point. */
break;
}
/* Is this entry obsolete? */
if ((list_word & LX_NOR_PHYSICAL_SECTOR_VALID) == 0)
{
/* Increment the number of obsolete sectors. */
obsolete_sectors++;
}
else
{
/* Increment the number of mapped sectors. */
mapped_sectors++;
}
/* Move the list pointer ahead. */
list_word_ptr++;
}
/* Determine if we have a block with a new maximum number of obsolete sectors. */
if ((obsolete_sectors > max_obsolete_sectors) && (erase_count <= erase_count_threshold))
{
/* Update the new maximum obsolete sectors and related information. */
max_obsolete_sectors = obsolete_sectors;
max_obsolete_block = i;
max_obsolete_erase_count = erase_count;
max_obsolete_mapped_count = mapped_sectors;
}
else if ((max_obsolete_sectors) && (obsolete_sectors == max_obsolete_sectors) && (erase_count <= erase_count_threshold))
{
/* Another block has the same number of obsolete sectors. Does this new block have a smaller erase
count? */
if (erase_count < max_obsolete_erase_count)
{
/* Yes, erase the block with the smaller erase count. */
max_obsolete_sectors = obsolete_sectors;
max_obsolete_block = i;
max_obsolete_erase_count = erase_count;
max_obsolete_mapped_count = mapped_sectors;
}
}
/* Determine if we have a new minimum erase count. */
if (erase_count < min_block_erase_count)
{
/* Update the new minimum erase count and related information. */
min_block_erase_count = erase_count;
min_block_erase = i;
min_block_obsolete_count = obsolete_sectors;
min_block_mapped_count = mapped_sectors;
}
/* Move to the next block. */
block_word_ptr = block_word_ptr + nor_flash -> lx_nor_flash_words_per_block;
}
/* Determine if we can erase the block with the most obsolete sectors. */
if (max_obsolete_sectors)
{
/* Erase the block with the most obsolete sectors. */
*return_erase_block = max_obsolete_block;
*return_erase_count = max_obsolete_erase_count;
*return_obsolete_sectors = max_obsolete_sectors;
*return_mapped_sectors = max_obsolete_mapped_count;
}
else
{
/* Otherwise, choose the block with the smallest erase count. */
*return_erase_block = min_block_erase;
*return_erase_count = min_block_erase_count;
*return_obsolete_sectors = min_block_obsolete_count;
*return_mapped_sectors = min_block_mapped_count;
}
/* Update the overall minimum and maximum erase count. */
nor_flash -> lx_nor_flash_minimum_erase_count = min_system_block_erase_count;
nor_flash -> lx_nor_flash_maximum_erase_count = max_system_block_erase_count;
/* Return success. */
return(LX_SUCCESS);
}
+872
View File
@@ -0,0 +1,872 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_open PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function opens a NOR flash instance and ensures the NOR flash */
/* is in a coherent state. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* name Name of NOR flash instance */
/* nor_driver_initialize Driver initialize */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* (nor_driver_initialize) Driver initialize */
/* _lx_nor_flash_driver_read Driver read */
/* _lx_nor_flash_driver_write Driver write */
/* (lx_nor_flash_driver_block_erased_verify) */
/* NOR flash verify block erased */
/* _lx_nor_flash_driver_block_erase Driver block erase */
/* _lx_nor_flash_logical_sector_find Find logical sector */
/* _lx_nor_flash_system_error System error handler */
/* tx_mutex_create Create thread-safe mutex */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_open(LX_NOR_FLASH *nor_flash, CHAR *name, UINT (*nor_driver_initialize)(LX_NOR_FLASH *))
{
ULONG sectors_per_block;
ULONG sector_map_words;
ULONG bit_map_words;
ULONG bit_map_mask;
ULONG total_header_words;
ULONG header_sectors;
ULONG *block_word_ptr;
ULONG block_word;
ULONG temp;
ULONG free_sectors;
ULONG used_sectors;
ULONG *new_map_entry;
ULONG *new_sector_address;
ULONG erased_count, min_erased_count, max_erased_count, temp_erased_count;
ULONG i, j, k;
UINT status;
#ifdef LX_FREE_SECTOR_DATA_VERIFY
ULONG *sector_word_ptr;
ULONG sector_word;
#endif
LX_NOR_FLASH *tail_ptr;
TX_INTERRUPT_SAVE_AREA
LX_PARAMETER_NOT_USED(name);
/* Clear the NOR flash control block. */
TX_MEMSET(nor_flash, 0, sizeof(LX_NOR_FLASH));
/* Call the flash driver's initialization function. */
(nor_driver_initialize)(nor_flash);
#ifndef LX_DIRECT_READ
/* Determine if the driver supplied a RAM buffer for reading the NOR sector if direct read is not
supported. */
if (nor_flash -> lx_nor_flash_sector_buffer == LX_NULL)
{
/* Return an error. */
return(LX_NO_MEMORY);
}
#endif
/* Setup the offset to the free bit map. */
nor_flash -> lx_nor_flash_block_free_bit_map_offset = sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG);
/* Calculate the number of bits we need in the free physical sector bit map. Subtract 1 to account for the
flash block header itself. The case where multiple physical sectors are needed for certain sized flash
devices is handled below. */
sectors_per_block = (nor_flash -> lx_nor_flash_words_per_block / LX_NOR_SECTOR_SIZE) - 1;
/* Calculate the number of words required for the sector map array. */
sector_map_words = sectors_per_block;
/* Calculate the number of words we need for the free physical sector bit map. */
bit_map_words = (sectors_per_block + 31)/ 32;
/* Save the number of bit map words. */
nor_flash -> lx_nor_flash_block_bit_map_words = bit_map_words;
/* Setup the offset (in words) to the array of physical sector mapping. */
nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset = nor_flash -> lx_nor_flash_block_free_bit_map_offset + bit_map_words;
/* Calculate the total number of words required for the flash block header. */
total_header_words = sizeof(LX_NOR_FLASH_BLOCK_HEADER)/sizeof(ULONG) + bit_map_words + sector_map_words;
/* Determine if more physical sectors are needed, which can happen on large devices. */
if (total_header_words <= LX_NOR_SECTOR_SIZE)
{
/* Round up to the size of 1 physical sector. */
total_header_words = LX_NOR_SECTOR_SIZE;
}
else
{
/* Otherwise calculate how many header sectors are necessary. */
header_sectors = (total_header_words-1)/LX_NOR_SECTOR_SIZE;
/* Round up to the next sector. */
header_sectors++;
/* Compute the total header words, rounding to the next sector. */
total_header_words = header_sectors * LX_NOR_SECTOR_SIZE;
/* Adjust the number of sectors per block. */
sectors_per_block = sectors_per_block - (header_sectors - 1);
}
/* Save the offset to the sector area. */
nor_flash -> lx_nor_flash_block_physical_sector_offset = total_header_words;
/* Save the physical sectors per block and total physical sectors. */
nor_flash -> lx_nor_flash_physical_sectors_per_block = sectors_per_block;
nor_flash -> lx_nor_flash_total_physical_sectors = nor_flash -> lx_nor_flash_total_blocks * sectors_per_block;
/* Build the free bit map mask, for the portion of the bit map that is less than 32 bits. */
if ((sectors_per_block % 32) != 0)
{
bit_map_mask = (ULONG)(1 << (sectors_per_block % 32));
bit_map_mask = bit_map_mask - 1;
}
else
{
/* Exactly 32 sectors for the bit map mask. */
bit_map_mask = LX_ALL_ONES;
}
/* Save the free bit map mask in the control block. */
nor_flash -> lx_nor_flash_block_bit_map_mask = bit_map_mask;
/* Setup default values for the max/min erased counts. */
min_erased_count = LX_ALL_ONES;
max_erased_count = 0;
/* Setup the block word pointer to the first word of the first block, which is effectively the
flash base address. */
block_word_ptr = nor_flash -> lx_nor_flash_base_address;
/* Loop through the blocks to determine the minimum and maximum erase count. */
for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
{
/* Pickup the first word of the block. If the flash manager has executed before, this word contains the
erase count for the block. Otherwise, if the word is 0xFFFFFFFF, this flash block was either erased
or this is the first time it was used. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
block_word = *block_word_ptr;
#else
status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
#endif
/* Is the block erased? */
if (((block_word & LX_BLOCK_ERASED) != LX_BLOCK_ERASED) && (block_word != LX_BLOCK_ERASE_STARTED))
{
/* No, valid block. Isolate the erased count. */
erased_count = (block_word & LX_BLOCK_ERASE_COUNT_MASK);
/* Is this the new minimum? */
if (erased_count < min_erased_count)
{
/* Yes, remember the new minimum. */
min_erased_count = erased_count;
}
/* Is this the new maximum? */
if (erased_count > max_erased_count)
{
/* Yes, remember the new maximum. */
max_erased_count = erased_count;
}
}
/* Move to the next flash block. */
block_word_ptr = block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
}
/* If we haven't found any erased counts, we can assume the flash is completely erased and needs to
be setup for the first time. */
if (min_erased_count == LX_ALL_ONES)
{
/* Indicate that this is the initial format. */
nor_flash -> lx_nor_flash_diagnostic_initial_format = LX_TRUE;
/* Setup the block word pointer to the first word of the first block, which is effectively the
flash base address. */
block_word_ptr = nor_flash -> lx_nor_flash_base_address;
/* Loop through the blocks to setup the flash the fist time. */
for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
{
/* Setup the free bit map that corresponds to the free physical sectors in this
block. Note that we only need to setup the portion of the free bit map that doesn't
have sectors associated with it. */
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (bit_map_words-1)) , &bit_map_mask, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
/* Setup the initial erase count to 1. */
block_word = ((ULONG) 1);
/* Write the initial erase count for the block. */
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
/* Update the overall minimum and maximum erase count. */
nor_flash -> lx_nor_flash_minimum_erase_count = 1;
nor_flash -> lx_nor_flash_maximum_erase_count = 1;
/* Update the number of free physical sectors. */
nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + sectors_per_block;
/* Move to the next flash block. */
block_word_ptr = block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
}
}
else
{
/* At this point, we have a previously managed flash structure. This needs to be traversed to prepare for the
current flash operation. */
/* Default the flash free sector search to an invalid value. */
nor_flash -> lx_nor_flash_free_block_search = nor_flash -> lx_nor_flash_total_blocks;
/* Setup the block word pointer to the first word of the first block, which is effectively the
flash base address. */
block_word_ptr = nor_flash -> lx_nor_flash_base_address;
/* Loop through the blocks. */
for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
{
/* First, determine if this block has a valid erase count. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
block_word = *block_word_ptr;
#else
status = _lx_nor_flash_driver_read(nor_flash, block_word_ptr, &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
#endif
/* Is the block erased? */
if (((block_word & LX_BLOCK_ERASED) == LX_BLOCK_ERASED) || (block_word == LX_BLOCK_ERASE_STARTED))
{
/* This can happen if we were previously in the process of erasing the flash block and a
power interruption occurs. It should only occur once though. */
/* Is this the first time? */
if (nor_flash -> lx_nor_flash_diagnostic_erased_block)
{
/* No, this is a potential format error, since this should only happen once in a given
NOR flash format. */
_lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
/* Return an error. */
return(LX_ERROR);
}
/* Increment the erased block diagnostic. */
nor_flash -> lx_nor_flash_diagnostic_erased_block++;
/* Check to see if the block is erased. */
status = (nor_flash -> lx_nor_flash_driver_block_erased_verify)(i);
/* Is the block completely erased? */
if (status != LX_SUCCESS)
{
/* Is this the first time? */
if (nor_flash -> lx_nor_flash_diagnostic_re_erase_block)
{
/* No, this is a potential format error, since this should only happen once in a given
NOR flash format. */
_lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
/* Return an error. */
return(LX_ERROR);
}
/* Increment the erased block diagnostic. */
nor_flash -> lx_nor_flash_diagnostic_re_erase_block++;
/* No, the block is not fully erased, erase it again. */
status = _lx_nor_flash_driver_block_erase(nor_flash, i, max_erased_count);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
}
/* Setup the free bit map that corresponds to the free physical sectors in this
block. Note that we only need to setup the portion of the free bit map that doesn't
have sectors associated with it. */
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr+(nor_flash -> lx_nor_flash_block_free_bit_map_offset + (bit_map_words-1)) , &bit_map_mask, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
/* Write the initial erase count for the block with upper bit set. */
temp_erased_count = (max_erased_count | LX_BLOCK_ERASED);
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &temp_erased_count, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
/* Write the final initial erase count for the block. */
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr, &max_erased_count, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
/* Update the number of free physical sectors. */
nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + sectors_per_block;
}
else
{
/* Calculate the number of free sectors from the free sector bit map. */
free_sectors = 0;
for (j = 0; j < bit_map_words; j++)
{
/* Read this word of the free sector bit map. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
block_word = *(block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j);
#else
status = _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j), &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
#endif
/* Count the number of set bits (free sectors). */
for (k = 0; k < 32; k++)
{
/* Is this sector free? */
if (block_word & 1)
{
/* Yes, this sector is free, increment the free sectors count. */
free_sectors++;
/* Determine if we need to update the search pointer. */
if (nor_flash -> lx_nor_flash_free_block_search == nor_flash -> lx_nor_flash_total_blocks)
{
/* Remember the block with free sectors. */
nor_flash -> lx_nor_flash_free_block_search = i;
}
}
/* Shift down the free sector. */
block_word = block_word >> 1;
}
}
/* Update the number of free physical sectors. */
nor_flash -> lx_nor_flash_free_physical_sectors = nor_flash -> lx_nor_flash_free_physical_sectors + free_sectors;
/* We need to now examine the mapping list. */
/* Calculate how many non-free sectors there are - this includes valid and obsolete sectors. */
used_sectors = sectors_per_block - free_sectors;
/* Now walk the list of logical-physical sector mapping. */
for (j = 0; j < sectors_per_block; j++)
{
/* Read this word of the sector mapping list. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
block_word = *(block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j);
#else
status = _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
#endif
/* Determine if we are expecting to find a used sector. */
if (used_sectors)
{
/* Yes, we expect this entry to be used. */
/* Is this sector in-use? */
if ((block_word & LX_NOR_LOGICAL_SECTOR_MASK) != LX_NOR_LOGICAL_SECTOR_MASK)
{
/* Determine if the valid bit is set and the superceded bit is clear. This indicates the block was
about to become obsolete. */
if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) && ((block_word & LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) == 0))
{
/* Increment the being obsoleted count. */
nor_flash -> lx_nor_flash_diagnostic_sector_being_obsoleted++;
/* Save the currently mapped physical sectors. */
temp = nor_flash -> lx_nor_flash_mapped_physical_sectors;
/* Indicate all the physical sectors are mapped for the purpose of this search. */
nor_flash -> lx_nor_flash_mapped_physical_sectors = nor_flash -> lx_nor_flash_total_physical_sectors;
/* Yes, this block was about to become obsolete. Perform a search for a logical sector entry that
has both of these bits set. */
_lx_nor_flash_logical_sector_find(nor_flash, (block_word & LX_NOR_LOGICAL_SECTOR_MASK), LX_TRUE, &new_map_entry, &new_sector_address);
/* Restore the number of mapped physical sectors. */
nor_flash -> lx_nor_flash_mapped_physical_sectors = temp;
/* Determine if the new logical sector entry is present. */
if (new_map_entry)
{
/* Yes, make the current entry obsolete in favor of the new entry. */
block_word = block_word & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
status = _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
/* Is this the first time? */
if (nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted)
{
/* No, this is a potential format error, since this should only happen once in a given
NOR flash format. */
_lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
/* Return an error. */
return(LX_ERROR);
}
/* Increment the obsoleted count. */
nor_flash -> lx_nor_flash_diagnostic_sector_obsoleted++;
}
}
}
/* Determine if the sector is free. */
else if (block_word == LX_NOR_PHYSICAL_SECTOR_FREE)
{
/* A free entry when there are still used sectors implies that the sector was allocated and a power interruption
took place prior to writing the new logical sector number into the list. */
/* Is this the first time? */
if (nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated)
{
/* No, this is a potential format error, since this should only happen once in a given
NOR flash format. */
_lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
/* Return an error. */
return(LX_ERROR);
}
/* Write 0s out to this entry to invalidate the sector entry. */
block_word = 0;
status = _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
/* Increment the number of mapping invalidates. */
nor_flash -> lx_nor_flash_diagnostic_mapping_invalidated++;
}
/* Yes, now determine if the sector is obsolete. */
if ((block_word & LX_NOR_PHYSICAL_SECTOR_VALID) == 0)
{
/* Increment the number of obsolete sectors. */
nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
}
/* Determine if the mapping for this sector isn't yet valid. */
else if (block_word & LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID)
{
/* Yes, a power interruption or reset occurred while the sector mapping entry was being written. */
/* Increment the number of obsolete sectors. */
nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
/* Increment the interrupted mapping counter. */
nor_flash -> lx_nor_flash_diagnostic_mapping_write_interrupted++;
/* Invalidate this entry - clearing valid bit, superceded bit and logical sector. */
block_word = 0;
status = _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
}
else
{
/* Increment the number of mapped physical sectors. */
nor_flash -> lx_nor_flash_mapped_physical_sectors++;
}
/* Decrease the number of used sectors. */
used_sectors--;
}
else
{
/* No more used sectors in this flash block. */
/* In this case the entry must be free or there is a serious NOR flash format error present. */
if (block_word != LX_NOR_PHYSICAL_SECTOR_FREE)
{
/* Increment the sector not free diagnostic. */
nor_flash -> lx_nor_flash_diagnostic_sector_not_free++;
/* NOR flash format. */
_lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_FORMAT);
/* Write 0s out to this entry to invalidate the sector entry. */
block_word = 0;
status = _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j), &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
}
#ifdef LX_FREE_SECTOR_DATA_VERIFY
/* Pickup address of the free sector data area. */
sector_word_ptr = block_word_ptr + (nor_flash -> lx_nor_flash_block_physical_sector_offset) + (j * LX_NOR_SECTOR_SIZE);
/* Determine if the data for this sector is free. */
for (k = 0; k < LX_NOR_SECTOR_SIZE; k++)
{
#ifdef LX_DIRECT_READ
/* Read the word directly. */
sector_word = *(sector_word_ptr);
#else
status = _lx_nor_flash_driver_read((sector_word_ptr), &sector_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return an error. */
return(LX_ERROR);
}
#endif
/* Determine if this word is not available. */
if (sector_word != LX_NOR_PHYSICAL_SECTOR_FREE)
{
/* Increment the sector data not free diagnostic. */
nor_flash -> lx_nor_flash_diagnostic_sector_data_not_free++;
/* This is a format error. */
_lx_nor_flash_system_error(nor_flash, LX_SYSTEM_INVALID_BLOCK);
/* Return an error. */
return(LX_ERROR);
}
/* Move to the next word in the sector. */
sector_word_ptr++;
}
#endif
}
}
}
/* Move to the next flash block. */
block_word_ptr = block_word_ptr + (nor_flash -> lx_nor_flash_words_per_block);
}
/* Update the overall minimum and maximum erase count. */
nor_flash -> lx_nor_flash_minimum_erase_count = min_erased_count;
nor_flash -> lx_nor_flash_maximum_erase_count = max_erased_count;
/* Determine if we need to update the free sector search pointer. */
if (nor_flash -> lx_nor_flash_free_block_search == nor_flash -> lx_nor_flash_total_blocks)
{
/* Just start at the beginning. */
nor_flash -> lx_nor_flash_free_block_search = 0;
}
}
#ifdef LX_THREAD_SAFE_ENABLE
/* If the thread safe option is enabled, create a ThreadX mutex that will be used in all external APIs
in order to provide thread-safe operation. */
status = tx_mutex_create(&nor_flash -> lx_nor_flash_mutex, "NOR Flash Mutex", TX_NO_INHERIT);
/* Determine if the mutex creation encountered an error. */
if (status != TX_SUCCESS)
{
/* Call system error handler, since this should not happen. */
_lx_nor_flash_system_error(nor_flash, LX_SYSTEM_MUTEX_CREATE_FAILED);
/* Return error to caller. */
return(LX_ERROR);
}
#endif
/* Enable the sector mapping cache. */
nor_flash -> lx_nor_flash_sector_mapping_cache_enabled = LX_TRUE;
/* Initialize the last found block and sector markers. */
nor_flash -> lx_nor_flash_found_block_search = 0;
nor_flash -> lx_nor_flash_found_sector_search = 0;
/* Lockout interrupts. */
TX_DISABLE
/* At this point, the NOR flash has been opened successfully. Place the
NOR flash control block on the linked list of currently opened NOR flashes. */
/* Set the NOR flash state to open. */
nor_flash -> lx_nor_flash_state = LX_NOR_FLASH_OPENED;
/* Place the NOR flash control block on the list of opened NOR flashes. First,
check for an empty list. */
if (_lx_nor_flash_opened_count)
{
/* List is not empty - other NOR flashes are open. */
/* Pickup tail pointer. */
tail_ptr = _lx_nor_flash_opened_ptr -> lx_nor_flash_open_previous;
/* Place the new NOR flash control block in the list. */
_lx_nor_flash_opened_ptr -> lx_nor_flash_open_previous = nor_flash;
tail_ptr -> lx_nor_flash_open_next = nor_flash;
/* Setup this NOR flash's opened links. */
nor_flash -> lx_nor_flash_open_previous = tail_ptr;
nor_flash -> lx_nor_flash_open_next = _lx_nor_flash_opened_ptr;
}
else
{
/* The opened NOR flash list is empty. Add the NOR flash to empty list. */
_lx_nor_flash_opened_ptr = nor_flash;
nor_flash -> lx_nor_flash_open_next = nor_flash;
nor_flash -> lx_nor_flash_open_previous = nor_flash;
}
/* Increment the opened NOR flash counter. */
_lx_nor_flash_opened_count++;
/* Restore interrupts. */
TX_RESTORE
/* Return a successful completion. */
return(LX_SUCCESS);
}
@@ -0,0 +1,123 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_partial_defragment PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function defragments the NOR flash up to the specified */
/* number of blocks. . */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* max_blocks Maximum number of blocks to */
/* defragment */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nor_flash_block_reclaim Reclaim a NOR flash block */
/* tx_mutex_get Get thread protection */
/* tx_mutex_put Release thread protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_partial_defragment(LX_NOR_FLASH *nor_flash, UINT max_blocks)
{
ULONG i;
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Determine if the maximum number of blocks exceeds the total blocks in this flash instance. */
if (max_blocks >= nor_flash -> lx_nor_flash_total_blocks)
{
/* Adjust the maximum to the total number of blocks. */
max_blocks = nor_flash -> lx_nor_flash_total_blocks;
}
/* Loop for max number of blocks, while there are obsolete count. */
for (i = 0; i < max_blocks; i++)
{
/* Determine if there is any more defragment work. */
if (nor_flash -> lx_nor_flash_obsolete_physical_sectors == 0)
break;
/* Call the block reclaim function to defragment. */
_lx_nor_flash_block_reclaim(nor_flash);
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return successful completion. */
return(LX_SUCCESS);
}
@@ -0,0 +1,337 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_physical_sector_allocate PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function allocates a free physical sector for mapping to a */
/* logical sector. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* logical_sector Logical sector number */
/* physical_sector_map_entry Pointer to sector map entry */
/* physical_sector_address Address of physical sector */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nor_flash_driver_write Driver flash sector write */
/* _lx_nor_flash_driver_read Driver flash sector read */
/* _lx_nor_flash_system_error Internal system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_physical_sector_allocate(LX_NOR_FLASH *nor_flash, ULONG logical_sector, ULONG **physical_sector_map_entry, ULONG **physical_sector_address)
{
ULONG search_block;
ULONG *block_word_ptr;
ULONG block_word;
ULONG min_logical_sector;
ULONG max_logical_sector;
ULONG *list_word_ptr;
ULONG list_word;
ULONG i, j, k, l;
UINT status;
/* Increment the number of physical sector allocation requests. */
nor_flash -> lx_nor_flash_physical_block_allocates++;
/* Initialize the return parameters. */
*physical_sector_map_entry = (ULONG *) 0;
*physical_sector_address = (ULONG *) 0;
/* Determine if there are any free physical sectors. */
if (nor_flash -> lx_nor_flash_free_physical_sectors == 0)
{
/* Increment the number of failed allocations. */
nor_flash -> lx_nor_flash_physical_block_allocate_errors++;
/* No free physical sectors, return . */
return(LX_NO_SECTORS);
}
/* Pickup the search for a free physical sector at the specified block. */
search_block = nor_flash -> lx_nor_flash_free_block_search;
/* Loop through the blocks to find a free physical sector. */
for (i = 0; i < nor_flash -> lx_nor_flash_total_blocks; i++)
{
/* Setup the block word pointer to the first word of the search block. */
block_word_ptr = nor_flash -> lx_nor_flash_base_address + (search_block * nor_flash -> lx_nor_flash_words_per_block);
/* Find the first free physical sector from the free sector bit map of this block. */
for (j = 0; j < nor_flash -> lx_nor_flash_block_bit_map_words; j++)
{
/* Read this word of the free sector bit map. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
block_word = *(block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j);
#else
status = _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j), &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Are there any free sectors in this word? */
if (block_word)
{
/* Yes, there are free sectors in this word. */
for (k = 0; k < 32; k++)
{
/* Is this sector free? */
if (block_word & 1)
{
/* Yes, this sector is free, clear the bit for this sector in the free sector map. */
/* Read this word of the free sector bit map again. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
block_word = *(block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j);
#else
status = _lx_nor_flash_driver_read(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j), &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Clear the bit associated with the free sector to indicate it is not free. */
block_word = block_word & ~(((ULONG) 1) << k);
/* Now write back free bit map word with the bit for this sector cleared. */
status = _lx_nor_flash_driver_write(nor_flash, (block_word_ptr + nor_flash -> lx_nor_flash_block_free_bit_map_offset + j), &block_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
/* Determine if this is the last entry available in this block. */
if (((block_word >> 1) == 0) && (j == (nor_flash -> lx_nor_flash_block_bit_map_words - 1)))
{
/* This is the last physical sector in the block. Now we need to calculate the minimum valid logical
sector and the maximum valid logical sector. */
/* Setup the minimum and maximum logical sectors to the current logical sector. */
min_logical_sector = logical_sector;
max_logical_sector = logical_sector;
/* Setup a pointer to the mapped list. */
list_word_ptr = block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset;
/* Loop to search the mapped list. */
for (l = 0; l < nor_flash -> lx_nor_flash_physical_sectors_per_block; l++)
{
/* Read the mapped sector entry. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
list_word = *(list_word_ptr);
#else
status = _lx_nor_flash_driver_read(nor_flash, list_word_ptr, &list_word, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
#endif
/* Is this entry valid? */
if (list_word & LX_NOR_PHYSICAL_SECTOR_VALID)
{
/* Isolate the logical sector. */
list_word = list_word & LX_NOR_LOGICAL_SECTOR_MASK;
/* Determine if a new minimum has been found. */
if (list_word < min_logical_sector)
min_logical_sector = list_word;
/* Determine if a new maximum has been found. */
if (list_word != LX_NOR_LOGICAL_SECTOR_MASK)
{
if (list_word > max_logical_sector)
max_logical_sector = list_word;
}
}
/* Move the list pointer ahead. */
list_word_ptr++;
}
/* Move the search pointer forward, since we know this block is exhausted. */
search_block++;
/* Check for wrap condition on the search block. */
if (search_block >= nor_flash -> lx_nor_flash_total_blocks)
{
/* Reset search block to the beginning. */
search_block = 0;
}
/* Now write the minimum and maximum logical sector in this block. */
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr + LX_NOR_FLASH_MIN_LOGICAL_SECTOR_OFFSET, &min_logical_sector, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
status = _lx_nor_flash_driver_write(nor_flash, block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET, &max_logical_sector, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Return the error. */
return(status);
}
}
/* Remember the block to search. */
nor_flash -> lx_nor_flash_free_block_search = search_block;
/* Prepare the return information. */
*physical_sector_map_entry = block_word_ptr + (nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + (j * 32)) + k;
*physical_sector_address = block_word_ptr + (nor_flash -> lx_nor_flash_block_physical_sector_offset) + (((j * 32) + k) * LX_NOR_SECTOR_SIZE);
/* Return success! */
return(LX_SUCCESS);
}
/* Shift down the bit map. */
block_word = block_word >> 1;
/* Determine if there are any more bits set? If not, we can break out of the search of this word. */
if (block_word == 0)
break;
}
}
}
/* Move to the next flash block. */
search_block++;
/* Determine if we have to wrap the search block. */
if (search_block >= nor_flash -> lx_nor_flash_total_blocks)
{
/* Set the search block to the beginning. */
search_block = 0;
}
}
/* Increment the number of failed allocations. */
nor_flash -> lx_nor_flash_physical_block_allocate_errors++;
/* Return no sector completion. */
return(LX_NO_SECTORS);
}
@@ -0,0 +1,134 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_sector_mapping_cache_invalidate PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function invalidates the sector's entry in the NOR flash */
/* cache. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* logical_sector Logical sector */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
VOID _lx_nor_flash_sector_mapping_cache_invalidate(LX_NOR_FLASH *nor_flash, ULONG logical_sector)
{
ULONG i;
LX_NOR_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr;
/* Determine if the sector mapping cache is enabled. */
if (nor_flash -> lx_nor_flash_sector_mapping_cache_enabled)
{
/* Calculate the starting index of the sector mapping cache for this sector entry. */
i = (logical_sector & LX_NOR_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NOR_SECTOR_MAPPING_CACHE_DEPTH;
/* Build a pointer to the cache entry. */
sector_mapping_cache_entry_ptr = &nor_flash -> lx_nor_flash_sector_mapping_cache[i];
/* Determine if the sector is in the sector mapping cache - assuming the depth of the sector
mapping cache is LX_NOR_SECTOR_MAPPING_CACHE_DEPTH entries. */
if ((sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_logical_sector) == (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Move all cache entries up and invalidate the last entry. */
*(sector_mapping_cache_entry_ptr) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 3);
/* Invalidate the last entry. */
(sector_mapping_cache_entry_ptr + 3) -> lx_nor_sector_mapping_cache_logical_sector = 0;
}
else if (((sector_mapping_cache_entry_ptr + 1) -> lx_nor_sector_mapping_cache_logical_sector) == (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Move all subsequent cache entries up and invalidate the last entry. */
*(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 3);
/* Invalidate the last entry. */
(sector_mapping_cache_entry_ptr + 3) -> lx_nor_sector_mapping_cache_logical_sector = 0;
}
else if (((sector_mapping_cache_entry_ptr + 2) -> lx_nor_sector_mapping_cache_logical_sector) == (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Move all subsequent cache entries up and invalidate the last entry. */
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 3);
/* Invalidate the last entry. */
(sector_mapping_cache_entry_ptr + 3) -> lx_nor_sector_mapping_cache_logical_sector = 0;
}
else if (((sector_mapping_cache_entry_ptr + 3) -> lx_nor_sector_mapping_cache_logical_sector) == (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID))
{
/* Simply invalidate the last entry. */
(sector_mapping_cache_entry_ptr + 3) -> lx_nor_sector_mapping_cache_logical_sector = 0;
}
}
}
+202
View File
@@ -0,0 +1,202 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_sector_read PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function reads a logical sector from NOR flash. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* logical_sector Logical sector number */
/* buffer Pointer to buffer to read into*/
/* (the size is 512 bytes) */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nor_flash_driver_write Driver flash sector write */
/* _lx_nor_flash_driver_read Driver flash sector read */
/* _lx_nor_flash_logical_sector_find Find logical sector */
/* _lx_nor_flash_physical_sector_allocate */
/* Allocate new logical sector */
/* _lx_nor_flash_system_error Internal system error handler */
/* tx_mutex_get Get thread protection */
/* tx_mutex_put Release thread protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_sector_read(LX_NOR_FLASH *nor_flash, ULONG logical_sector, VOID *buffer)
{
UINT status;
ULONG *mapping_address;
ULONG mapping_entry;
ULONG *sector_address;
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Increment the number of read requests. */
nor_flash -> lx_nor_flash_read_requests++;
/* See if we can find the sector in the current mapping. */
_lx_nor_flash_logical_sector_find(nor_flash, logical_sector, LX_FALSE, &mapping_address, &sector_address);
/* Determine if the logical sector was found. */
if (mapping_address)
{
/* Yes, we were able to find the logical sector. */
/* Read the sector data from the physical sector. */
status = _lx_nor_flash_driver_read(nor_flash, sector_address, buffer, LX_NOR_SECTOR_SIZE);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
/* Adjust return status. */
status = LX_ERROR;
}
else
{
/* Set the status to success. */
status = LX_SUCCESS;
}
}
else
{
/* Allocate a new physical sector for this write. */
_lx_nor_flash_physical_sector_allocate(nor_flash, logical_sector, &mapping_address, &sector_address);
/* Determine if the new sector allocation was successful. */
if (mapping_address)
{
/* Update the number of free physical sectors. */
nor_flash -> lx_nor_flash_free_physical_sectors--;
/* Read the sector data from the physical sector. */
status = _lx_nor_flash_driver_read(nor_flash, sector_address, buffer, LX_NOR_SECTOR_SIZE);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
}
/* Now build the new mapping entry. */
mapping_entry = ((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) | logical_sector;
/* Write out the new mapping entry. */
status = _lx_nor_flash_driver_write(nor_flash, mapping_address, &mapping_entry, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(LX_ERROR);
}
/* Increment the number of mapped physical sectors. */
nor_flash -> lx_nor_flash_mapped_physical_sectors++;
/* Set the status to success. */
status = LX_SUCCESS;
}
else
{
/* Could not find the logical sector. */
status = LX_SECTOR_NOT_FOUND;
}
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(status);
}
+211
View File
@@ -0,0 +1,211 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_sector_release PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function releases a logical sector from being managed in the */
/* NOR flash. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* logical_sector Logical sector number */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nor_flash_driver_write Driver flash sector write */
/* _lx_nor_flash_driver_read Driver flash sector read */
/* _lx_nor_flash_block_reclaim Reclaim one flash block */
/* _lx_nor_flash_sector_mapping_cache_invalidate */
/* Invalidate cache entry */
/* _lx_nor_flash_logical_sector_find Find logical sector */
/* _lx_nor_flash_system_error Internal system error handler */
/* tx_mutex_get Get thread protection */
/* tx_mutex_put Release thread protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_sector_release(LX_NOR_FLASH *nor_flash, ULONG logical_sector)
{
UINT status;
ULONG *mapping_address;
ULONG mapping_entry;
ULONG *sector_address;
ULONG i;
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Increment the number of read requests. */
nor_flash -> lx_nor_flash_read_requests++;
/* See if we can find the sector in the current mapping. */
_lx_nor_flash_logical_sector_find(nor_flash, logical_sector, LX_FALSE, &mapping_address, &sector_address);
/* Determine if the logical sector was found. */
if (mapping_address)
{
/* Yes, we were able to find the logical sector. */
/* Read in the old sector mapping. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
mapping_entry = *(mapping_address);
#else
status = _lx_nor_flash_driver_read(nor_flash, mapping_address, &mapping_entry, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(LX_ERROR);
}
#endif
/* Mark this sector as invalid. */
/* Now clear bits 31 and 30, which indicates this sector is now obsoleted. */
mapping_entry = mapping_entry & ~(((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED));
/* Write the value back to the flash to clear bits 31 & 30. */
status = _lx_nor_flash_driver_write(nor_flash, mapping_address, &mapping_entry, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(LX_ERROR);
}
/* Increment the number of obsolete physical sectors. */
nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
/* Decrement the number of mapped physical sectors. */
nor_flash -> lx_nor_flash_mapped_physical_sectors--;
/* Ensure the sector mapping cache no longer has this sector. */
_lx_nor_flash_sector_mapping_cache_invalidate(nor_flash, logical_sector);
/* Determine if there are less than two block's worth of free sectors. */
i = 0;
while (nor_flash -> lx_nor_flash_free_physical_sectors <= nor_flash -> lx_nor_flash_physical_sectors_per_block)
{
/* Attempt to reclaim one physical block. */
_lx_nor_flash_block_reclaim(nor_flash);
/* Increment the block count. */
i++;
/* Have we exceeded the number of blocks in the system? */
if (i >= nor_flash -> lx_nor_flash_total_blocks)
{
/* Yes, break out of the loop. */
break;
}
}
/* Set the status to success. */
status = LX_SUCCESS;
}
else
{
/* Could not find the logical sector. */
status = LX_SECTOR_NOT_FOUND;
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(status);
}
+352
View File
@@ -0,0 +1,352 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_sector_write PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function writes a logical sector to the NOR flash. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* logical_sector Logical sector number */
/* buffer Pointer to buffer to write */
/* (the size is 512 bytes) */
/* */
/* OUTPUT */
/* */
/* return status */
/* */
/* CALLS */
/* */
/* _lx_nor_flash_driver_write Driver flash sector write */
/* _lx_nor_flash_driver_read Driver flash sector read */
/* _lx_nor_flash_block_reclaim Reclaim one flash block */
/* _lx_nor_flash_logical_sector_find Find logical sector */
/* _lx_nor_flash_physical_sector_allocate */
/* Allocate new physical sector */
/* _lx_nor_flash_sector_mapping_cache_invalidate */
/* Invalidate cache entry */
/* _lx_nor_flash_system_error Internal system error handler */
/* tx_mutex_get Get thread protection */
/* tx_mutex_put Release thread protection */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
UINT _lx_nor_flash_sector_write(LX_NOR_FLASH *nor_flash, ULONG logical_sector, VOID *buffer)
{
ULONG *old_mapping_address;
ULONG *old_sector_address;
ULONG old_mapping_entry;
ULONG *new_mapping_address;
ULONG *new_sector_address;
ULONG new_mapping_entry;
ULONG i;
LX_NOR_SECTOR_MAPPING_CACHE_ENTRY *sector_mapping_cache_entry_ptr;
UINT status;
#ifdef LX_THREAD_SAFE_ENABLE
/* Obtain the thread safe mutex. */
tx_mutex_get(&nor_flash -> lx_nor_flash_mutex, TX_WAIT_FOREVER);
#endif
/* Determine if there are less than two block's worth of free sectors. */
i = 0;
while (nor_flash -> lx_nor_flash_free_physical_sectors <= nor_flash -> lx_nor_flash_physical_sectors_per_block)
{
/* Attempt to reclaim one physical block. */
_lx_nor_flash_block_reclaim(nor_flash);
/* Increment the block count. */
i++;
/* Have we exceeded the number of blocks in the system? */
if (i >= nor_flash -> lx_nor_flash_total_blocks)
{
/* Yes, break out of the loop. */
break;
}
}
/* Increment the number of write requests. */
nor_flash -> lx_nor_flash_write_requests++;
/* See if we can find the sector in the current mapping. */
_lx_nor_flash_logical_sector_find(nor_flash, logical_sector, LX_FALSE, &old_mapping_address, &old_sector_address);
/* Allocate a new physical sector for this write. */
_lx_nor_flash_physical_sector_allocate(nor_flash, logical_sector, &new_mapping_address, &new_sector_address);
/* Determine if the new sector allocation was successful. */
if (new_mapping_address)
{
/* Yes, we were able to allocate a new physical sector. */
/* Update the number of free physical sectors. */
nor_flash -> lx_nor_flash_free_physical_sectors--;
/* Write the sector data to the new physical sector. */
status = _lx_nor_flash_driver_write(nor_flash, new_sector_address, buffer, LX_NOR_SECTOR_SIZE);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(LX_ERROR);
}
/* Was there a previously mapped sector? */
if (old_mapping_address)
{
/* Now deprecate the old sector mapping. */
/* Read in the old sector mapping. */
#ifdef LX_DIRECT_READ
/* Read the word directly. */
old_mapping_entry = *(old_mapping_address);
#else
status = _lx_nor_flash_driver_read(nor_flash, old_mapping_address, &old_mapping_entry, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(LX_ERROR);
}
#endif
/* Clear bit 30, which indicates this sector is superceded. */
old_mapping_entry = old_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED);
/* Write the value back to the flash to clear bit 30. */
status = _lx_nor_flash_driver_write(nor_flash, old_mapping_address, &old_mapping_entry, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(LX_ERROR);
}
}
/* Now build the new mapping entry - with the not valid bit set initially. */
new_mapping_entry = ((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_SUPERCEDED) | ((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID) | logical_sector;
/* Write out the new mapping entry. */
status = _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(LX_ERROR);
}
/* Now clear the not valid bit to make this sector mapping valid. This is done because the writing of the extra bytes itself can
be interrupted and we need to make sure this can be detected when the flash is opened again. */
new_mapping_entry = new_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID);
/* Clear the not valid bit. */
status = _lx_nor_flash_driver_write(nor_flash, new_mapping_address, &new_mapping_entry, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(LX_ERROR);
}
/* Increment the number of mapped physical sectors. */
nor_flash -> lx_nor_flash_mapped_physical_sectors++;
/* Was there a previously mapped sector? */
if (old_mapping_address)
{
/* Now clear bit 31, which indicates this sector is now obsoleted. */
old_mapping_entry = old_mapping_entry & ~((ULONG) LX_NOR_PHYSICAL_SECTOR_VALID);
/* Write the value back to the flash to clear bit 31. */
status = _lx_nor_flash_driver_write(nor_flash, old_mapping_address, &old_mapping_entry, 1);
/* Check for an error from flash driver. Drivers should never return an error.. */
if (status)
{
/* Call system error handler. */
_lx_nor_flash_system_error(nor_flash, status);
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return status. */
return(LX_ERROR);
}
/* Increment the number of obsolete physical sectors. */
nor_flash -> lx_nor_flash_obsolete_physical_sectors++;
/* Decrement the number of mapped physical sectors. */
nor_flash -> lx_nor_flash_mapped_physical_sectors--;
/* Invalidate the old sector mapping cache entry. */
_lx_nor_flash_sector_mapping_cache_invalidate(nor_flash, logical_sector);
}
/* Determine if the sector mapping cache is enabled. */
if (nor_flash -> lx_nor_flash_sector_mapping_cache_enabled)
{
/* Yes, sector mapping cache is enabled, place this sector information in the cache. */
/* Calculate the starting index of the sector mapping cache for this sector entry. */
i = (logical_sector & LX_NOR_SECTOR_MAPPING_CACHE_HASH_MASK) * LX_NOR_SECTOR_MAPPING_CACHE_DEPTH;
/* Build a pointer to the cache entry. */
sector_mapping_cache_entry_ptr = &nor_flash -> lx_nor_flash_sector_mapping_cache[i];
/* Move all the cache entries down so the oldest is at the bottom. */
*(sector_mapping_cache_entry_ptr + 3) = *(sector_mapping_cache_entry_ptr + 2);
*(sector_mapping_cache_entry_ptr + 2) = *(sector_mapping_cache_entry_ptr + 1);
*(sector_mapping_cache_entry_ptr + 1) = *(sector_mapping_cache_entry_ptr);
/* Setup the new sector information in the cache. */
sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_logical_sector = (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID);
sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_map_entry = new_mapping_address;
sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_address = new_sector_address;
}
/* Indicate the write was successful. */
status = LX_SUCCESS;
}
else
{
/* Indicate the write was unsuccessful. */
status = LX_NO_SECTORS;
}
#ifdef LX_THREAD_SAFE_ENABLE
/* Release the thread safe mutex. */
tx_mutex_put(&nor_flash -> lx_nor_flash_mutex);
#endif
/* Return the completion status. */
return(status);
}
+208
View File
@@ -0,0 +1,208 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash Simulator */
/** */
/**************************************************************************/
/**************************************************************************/
/* Include necessary files. */
#include "tx_api.h"
#include "lx_api.h"
/* Define constants for the NOR flash simulation. */
/* This configuration is for one physical sector of overhead. */
#define TOTAL_BLOCKS 8
#define PHYSICAL_SECTORS_PER_BLOCK 16 /* Min value of 2, max value of 120 for 1 sector of overhead. */
#define WORDS_PER_PHYSICAL_SECTOR 128
#define FREE_BIT_MAP_WORDS ((PHYSICAL_SECTORS_PER_BLOCK-1)/32)+1
#define USABLE_SECTORS_PER_BLOCK (PHYSICAL_SECTORS_PER_BLOCK-1)
#define UNUSED_METADATA_WORDS_PER_BLOCK (WORDS_PER_PHYSICAL_SECTOR-(3+FREE_BIT_MAP_WORDS+USABLE_SECTORS_PER_BLOCK))
typedef struct PHYSICAL_SECTOR_STRUCT
{
unsigned long memory[WORDS_PER_PHYSICAL_SECTOR];
} PHYSICAL_SECTOR;
typedef struct FLASH_BLOCK_STRUCT
{
unsigned long erase_count;
unsigned long min_log_sector;
unsigned long max_log_sector;
unsigned long free_bit_map[FREE_BIT_MAP_WORDS];
unsigned long sector_metadata[USABLE_SECTORS_PER_BLOCK];
unsigned long unused_words[UNUSED_METADATA_WORDS_PER_BLOCK];
PHYSICAL_SECTOR physical_sectors[USABLE_SECTORS_PER_BLOCK];
} FLASH_BLOCK;
FLASH_BLOCK nor_memory_area[TOTAL_BLOCKS];
ULONG nor_sector_memory[WORDS_PER_PHYSICAL_SECTOR];
UINT _lx_nor_flash_simulator_initialize(LX_NOR_FLASH *nor_flash);
UINT _lx_nor_flash_simulator_read(ULONG *flash_address, ULONG *destination, ULONG words);
UINT _lx_nor_flash_simulator_write(ULONG *flash_address, ULONG *source, ULONG words);
UINT _lx_nor_flash_simulator_block_erase(ULONG block, ULONG erase_count);
UINT _lx_nor_flash_simulator_block_erased_verify(ULONG block);
UINT _lx_nor_flash_simulator_erase_all(VOID);
UINT _lx_nor_flash_simulator_system_error(UINT error_code, ULONG block, ULONG sector);
UINT _lx_nor_flash_simulator_initialize(LX_NOR_FLASH *nor_flash)
{
/* Setup the base address of the flash memory. */
nor_flash -> lx_nor_flash_base_address = (ULONG *) &nor_memory_area[0];
/* Setup geometry of the flash. */
nor_flash -> lx_nor_flash_total_blocks = TOTAL_BLOCKS;
nor_flash -> lx_nor_flash_words_per_block = sizeof(FLASH_BLOCK)/sizeof(ULONG);
/* Setup function pointers for the NOR flash services. */
nor_flash -> lx_nor_flash_driver_read = _lx_nor_flash_simulator_read;
nor_flash -> lx_nor_flash_driver_write = _lx_nor_flash_simulator_write;
nor_flash -> lx_nor_flash_driver_block_erase = _lx_nor_flash_simulator_block_erase;
nor_flash -> lx_nor_flash_driver_block_erased_verify = _lx_nor_flash_simulator_block_erased_verify;
/* Setup local buffer for NOR flash operation. This buffer must be the sector size of the NOR flash memory. */
nor_flash -> lx_nor_flash_sector_buffer = &nor_sector_memory[0];
/* Return success. */
return(LX_SUCCESS);
}
UINT _lx_nor_flash_simulator_read(ULONG *flash_address, ULONG *destination, ULONG words)
{
/* Loop to read flash. */
while (words--)
{
/* Copy word. */
*destination++ = *flash_address++;
}
return(LX_SUCCESS);
}
UINT _lx_nor_flash_simulator_write(ULONG *flash_address, ULONG *source, ULONG words)
{
/* Loop to write flash. */
while (words--)
{
/* Copy word. */
*flash_address++ = *source++;
}
return(LX_SUCCESS);
}
UINT _lx_nor_flash_simulator_block_erase(ULONG block, ULONG erase_count)
{
ULONG *pointer;
ULONG words;
LX_PARAMETER_NOT_USED(erase_count);
/* Setup pointer. */
pointer = (ULONG *) &nor_memory_area[block];
/* Loop to erase block. */
words = sizeof(FLASH_BLOCK)/sizeof(ULONG);
while (words--)
{
/* Erase word of block. */
*pointer++ = (ULONG) 0xFFFFFFFF;
}
return(LX_SUCCESS);
}
UINT _lx_nor_flash_simulator_erase_all(VOID)
{
ULONG *pointer;
ULONG words;
/* Setup pointer. */
pointer = (ULONG *) &nor_memory_area[0];
/* Loop to erase block. */
words = sizeof(nor_memory_area)/sizeof(ULONG);
while (words--)
{
/* Erase word of block. */
*pointer++ = (ULONG) 0xFFFFFFFF;
}
return(LX_SUCCESS);
}
UINT _lx_nor_flash_simulator_block_erased_verify(ULONG block)
{
ULONG *word_ptr;
ULONG words;
/* Determine if the block is completely erased. */
/* Pickup the pointer to the first word of the block. */
word_ptr = (ULONG *) &nor_memory_area[block].erase_count;
/* Calculate the number of words in a block. */
words = sizeof(FLASH_BLOCK)/sizeof(ULONG);
/* Loop to check if the block is erased. */
while (words--)
{
/* Is this word erased? */
if (*word_ptr++ != 0xFFFFFFFF)
return(LX_ERROR);
}
/* Return success. */
return(LX_SUCCESS);
}
UINT _lx_nor_flash_simulator_system_error(UINT error_code, ULONG block, ULONG sector)
{
LX_PARAMETER_NOT_USED(error_code);
LX_PARAMETER_NOT_USED(block);
LX_PARAMETER_NOT_USED(sector);
/* Custom processing goes here... all errors are fatal. */
return(LX_ERROR);
}
+93
View File
@@ -0,0 +1,93 @@
/**************************************************************************/
/* */
/* 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. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** LevelX Component */
/** */
/** NOR Flash */
/** */
/**************************************************************************/
/**************************************************************************/
#define LX_SOURCE_CODE
/* Disable ThreadX error checking. */
#ifndef TX_DISABLE_ERROR_CHECKING
#define TX_DISABLE_ERROR_CHECKING
#endif
/* Include necessary system files. */
#include "lx_api.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _lx_nor_flash_system_error PORTABLE C */
/* 6.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function handles system errors in the NOR flash. */
/* */
/* INPUT */
/* */
/* nor_flash NOR flash instance */
/* error_code System error code */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* (lx_nor_flash_driver_system_error) Driver system error handler */
/* */
/* CALLED BY */
/* */
/* Internal LevelX */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* */
/**************************************************************************/
VOID _lx_nor_flash_system_error(LX_NOR_FLASH *nor_flash, UINT error_code)
{
/* Increment the system error counter. */
nor_flash -> lx_nor_flash_diagnostic_system_errors++;
/* Save the most recent system error code. */
nor_flash -> lx_nor_flash_diagnostic_system_error = error_code;
/* Determine if the driver has setup a system error handler. */
if (nor_flash -> lx_nor_flash_driver_system_error)
{
/* Yes, call the driver's system error handler. */
(nor_flash -> lx_nor_flash_driver_system_error)(error_code);
}
}
Binary file not shown.
BIN
View File
Binary file not shown.
+236
View File
@@ -0,0 +1,236 @@
/* This is a small demo of the high-performance FileX FAT file system with LevelX
and the NAND simulated driver. */
#include <stdio.h>
#include "fx_api.h"
#include "lx_api.h"
#define DEMO_STACK_SIZE 4096
/* Buffer for FileX FX_MEDIA sector cache. This must be large enough for at least one
sector, which are typically 512 bytes in size. */
unsigned char media_memory[4096];
/* Define NAND simulated device driver entry. */
VOID _fx_nand_flash_simulator_driver(FX_MEDIA *media_ptr);
/* Define LevelX NAND simulated flash erase. */
UINT _lx_nand_flash_simulator_erase_all(VOID);
/* Define thread prototypes. */
void thread_0_entry(ULONG thread_input);
UCHAR thread_0_stack[DEMO_STACK_SIZE];
/* Define FileX global data structures. */
FX_MEDIA nand_disk;
FX_FILE my_file;
FX_FILE my_file1;
/* Define ThreadX global data structures. */
TX_THREAD thread_0;
ULONG thread_0_counter;
int main(void)
{
/* Enter the ThreadX kernel. */
tx_kernel_enter();
}
/* Define what the initial system looks like. */
void tx_application_define(void *first_unused_memory)
{
/* Put system definition stuff in here, e.g. thread creates and other assorted
create information. */
/* Create the main thread. */
tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
thread_0_stack, DEMO_STACK_SIZE,
1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
/* Initialize NAND flash. */
lx_nand_flash_initialize();
/* Initialize FileX. */
fx_system_initialize();
}
void thread_0_entry(ULONG thread_input)
{
UINT status;
ULONG actual;
CHAR local_buffer[30];
LX_PARAMETER_NOT_USED(thread_input);
/* Erase the simulated NAND flash. */
_lx_nand_flash_simulator_erase_all();
/* Format the NAND disk - the memory for the NAND flash disk is setup in
the NAND simulator. Note that for best performance, the format of the
NAND flash should be less than one full NAND flash block of sectors. */
fx_media_format(&nand_disk,
_fx_nand_flash_simulator_driver, // Driver entry
FX_NULL, // Unused
media_memory, // Media buffer pointer
sizeof(media_memory), // Media buffer size
"MY_NAND_DISK", // Volume Name
1, // Number of FATs
32, // Directory Entries
0, // Hidden sectors
120, // Total sectors
2048, // Sector size
1, // Sectors per cluster
1, // Heads
1); // Sectors per track
/* Loop to repeat the demo over and over! */
do
{
/* Open the NAND disk. */
status = fx_media_open(&nand_disk, "NAND DISK", _fx_nand_flash_simulator_driver, FX_NULL, media_memory, sizeof(media_memory));
/* Check the media open status. */
if (status != FX_SUCCESS)
{
/* Error, break the loop! */
break;
}
/* Create a file called TEST.TXT in the root directory. */
status = fx_file_create(&nand_disk, "TEST.TXT");
/* Check the create status. */
if (status != FX_SUCCESS)
{
/* Check for an already created status. This is expected on the
second pass of this loop! */
if (status != FX_ALREADY_CREATED)
{
/* Create error, break the loop. */
break;
}
}
/* Open the test file. */
status = fx_file_open(&nand_disk, &my_file, "TEST.TXT", FX_OPEN_FOR_WRITE);
/* Check the file open status. */
if (status != FX_SUCCESS)
{
/* Error opening file, break the loop. */
break;
}
/* Seek to the beginning of the test file. */
status = fx_file_seek(&my_file, 0);
/* Check the file seek status. */
if (status != FX_SUCCESS)
{
/* Error performing file seek, break the loop. */
break;
}
/* Write a string to the test file. */
status = fx_file_write(&my_file, " ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", 28);
/* Check the file write status. */
if (status != FX_SUCCESS)
{
/* Error writing to a file, break the loop. */
break;
}
/* Seek to the beginning of the test file. */
status = fx_file_seek(&my_file, 0);
/* Check the file seek status. */
if (status != FX_SUCCESS)
{
/* Error performing file seek, break the loop. */
break;
}
/* Read the first 28 bytes of the test file. */
status = fx_file_read(&my_file, local_buffer, 28, &actual);
/* Check the file read status. */
if ((status != FX_SUCCESS) || (actual != 28))
{
/* Error reading file, break the loop. */
break;
}
/* Close the test file. */
status = fx_file_close(&my_file);
/* Check the file close status. */
if (status != FX_SUCCESS)
{
/* Error closing the file, break the loop. */
break;
}
/* Delete the file. */
status = fx_file_delete(&nand_disk, "TEST.TXT");
/* Check the file delete status. */
if (status != FX_SUCCESS)
{
/* Error deleting the file, break the loop. */
break;
}
/* Close the media. */
status = fx_media_close(&nand_disk);
/* Check the media close status. */
if (status != FX_SUCCESS)
{
/* Error closing the media, break the loop. */
break;
}
/* Increment the thread counter, which represents the number
of successful passes through this loop. */
thread_0_counter++;
} while (1);
/* If we get here the FileX test failed! */
return;
}
+235
View File
@@ -0,0 +1,235 @@
/* This is a small demo of the high-performance FileX FAT file system with LevelX
and the NOR simulated driver. */
#include "fx_api.h"
#include "lx_api.h"
#define DEMO_STACK_SIZE 2048
/* Buffer for FileX FX_MEDIA sector cache. This must be large enough for at least one
sector, which are typically 512 bytes in size. */
unsigned char media_memory[512];
/* Define NOR simulated device driver entry. */
VOID _fx_nor_flash_simulator_driver(FX_MEDIA *media_ptr);
/* Define LevelX NOR simulated flash erase. */
UINT _lx_nor_flash_simulator_erase_all(VOID);
/* Define thread prototypes. */
void thread_0_entry(ULONG thread_input);
UCHAR thread_0_stack[DEMO_STACK_SIZE];
/* Define FileX global data structures. */
FX_MEDIA nor_disk;
FX_FILE my_file;
/* Define ThreadX global data structures. */
TX_THREAD thread_0;
ULONG thread_0_counter;
int main(void)
{
/* Enter the ThreadX kernel. */
tx_kernel_enter();
}
/* Define what the initial system looks like. */
void tx_application_define(void *first_unused_memory)
{
/* Put system definition stuff in here, e.g. thread creates and other assorted
create information. */
/* Create the main thread. */
tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
thread_0_stack, DEMO_STACK_SIZE,
1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
/* Initialize NOR flash. */
lx_nor_flash_initialize();
/* Initialize FileX. */
fx_system_initialize();
}
void thread_0_entry(ULONG thread_input)
{
UINT status;
ULONG actual;
CHAR local_buffer[30];
LX_PARAMETER_NOT_USED(thread_input);
/* Erase the simulated NOR flash. */
_lx_nor_flash_simulator_erase_all();
/* Format the NOR disk - the memory for the NOR flash disk is setup in
the NOR simulator. Note that for best performance, the format of the
NOR flash should be less than one full NOR flash block of sectors. */
fx_media_format(&nor_disk,
_fx_nor_flash_simulator_driver, // Driver entry
FX_NULL, // Unused
media_memory, // Media buffer pointer
sizeof(media_memory), // Media buffer size
"MY_NOR_DISK", // Volume Name
1, // Number of FATs
32, // Directory Entries
0, // Hidden sectors
120, // Total sectors
512, // Sector size
1, // Sectors per cluster
1, // Heads
1); // Sectors per track
/* Loop to repeat the demo over and over! */
do
{
/* Open the NOR disk. */
status = fx_media_open(&nor_disk, "NOR DISK", _fx_nor_flash_simulator_driver, FX_NULL, media_memory, sizeof(media_memory));
/* Check the media open status. */
if (status != FX_SUCCESS)
{
/* Error, break the loop! */
break;
}
/* Create a file called TEST.TXT in the root directory. */
status = fx_file_create(&nor_disk, "TEST.TXT");
/* Check the create status. */
if (status != FX_SUCCESS)
{
/* Check for an already created status. This is expected on the
second pass of this loop! */
if (status != FX_ALREADY_CREATED)
{
/* Create error, break the loop. */
break;
}
}
/* Open the test file. */
status = fx_file_open(&nor_disk, &my_file, "TEST.TXT", FX_OPEN_FOR_WRITE);
/* Check the file open status. */
if (status != FX_SUCCESS)
{
/* Error opening file, break the loop. */
break;
}
/* Seek to the beginning of the test file. */
status = fx_file_seek(&my_file, 0);
/* Check the file seek status. */
if (status != FX_SUCCESS)
{
/* Error performing file seek, break the loop. */
break;
}
/* Write a string to the test file. */
status = fx_file_write(&my_file, " ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", 28);
/* Check the file write status. */
if (status != FX_SUCCESS)
{
/* Error writing to a file, break the loop. */
break;
}
/* Seek to the beginning of the test file. */
status = fx_file_seek(&my_file, 0);
/* Check the file seek status. */
if (status != FX_SUCCESS)
{
/* Error performing file seek, break the loop. */
break;
}
/* Read the first 28 bytes of the test file. */
status = fx_file_read(&my_file, local_buffer, 28, &actual);
/* Check the file read status. */
if ((status != FX_SUCCESS) || (actual != 28))
{
/* Error reading file, break the loop. */
break;
}
/* Close the test file. */
status = fx_file_close(&my_file);
/* Check the file close status. */
if (status != FX_SUCCESS)
{
/* Error closing the file, break the loop. */
break;
}
/* Delete the file. */
status = fx_file_delete(&nor_disk, "TEST.TXT");
/* Check the file delete status. */
if (status != FX_SUCCESS)
{
/* Error deleting the file, break the loop. */
break;
}
/* Close the media. */
status = fx_media_close(&nor_disk);
/* Check the media close status. */
if (status != FX_SUCCESS)
{
/* Error closing the media, break the loop. */
break;
}
/* Increment the thread counter, which represents the number
of successful passes through this loop. */
thread_0_counter++;
} while (1);
/* If we get here the FileX test failed! */
return;
}