1 /* 2 * Copyright (c) 2017-2019, Texas Instruments Incorporated 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of Texas Instruments Incorporated nor the names of 17 * its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /*!***************************************************************************** 34 * @file NVSSPI25X.h 35 * @brief Non-Volatile Storage driver implementation 36 * for SPI flash peripherals 37 * 38 * # Overview # 39 * 40 * The NVSSPI25X module allows you to manage SPI flash memory. 41 * This driver works with most 256 byte/page SPI flash memory devices 42 * such as: 43 * 44 * Winbond W25xx family 45 * Macronics MX25Rxx family 46 * Micron N25Qxx family 47 * 48 * The SPI flash commands used by this driver are as follows: 49 * 50 * @code 51 * #define SPIFLASH_PAGE_WRITE 0x02 // Page Program (up to 256 bytes) 52 * #define SPIFLASH_READ 0x03 // Read Data 53 * #define SPIFLASH_READ_STATUS 0x05 // Read Status Register 54 * #define SPIFLASH_WRITE_ENABLE 0x06 // Write Enable 55 * #define SPIFLASH_SUBSECTOR_ERASE 0x20 // SubSector (4K bytes) Erase 56 * #define SPIFLASH_SECTOR_ERASE 0xD8 // Sector (usually 64K bytes) Erase 57 * #define SPIFLASH_RDP 0xAB // Release from Deep Power Down 58 * #define SPIFLASH_DP 0xB9 // Deep Power Down 59 * #define SPIFLASH_MASS_ERASE 0xC7 // Erase entire flash. 60 * @endcode 61 * 62 * It is assumed that the SPI flash device used by this driver supports 63 * the byte programmability of the SPIFLASH_PAGE_WRITE command and that 64 * write page size is 256 bytes. The erase sector and subsector sizes are 65 * assumed to be 64K and 4K respectively. 66 * 67 * The NVS_erase() command will issue a sector or subsector erase command 68 * based on the input size and offset. 69 * 70 * The driver must query the SPI flash to ensure that the part is ready before 71 * commands are issued. If the part responds as busy, the poll function sleeps 72 * for a number of microseconds determined by the 73 * #NVSSPI25X_HWAttrs.statusPollDelayUs field. A value of 0 means that the 74 * driver will continuously poll the external flash until it is ready, which 75 * may affect other threads ability to execute. 76 * 77 * ## SPI Interface Management ## 78 * 79 * For each managed flash region, a corresponding SPI instance must be 80 * provided to the NVSSPI25X driver. 81 * 82 * The SPI instance can be opened and closed 83 * internally by the NVSSPI25X driver, or alternatively, a SPI handle can be 84 * provided to the NVSSPI25X driver, indicating that the SPI instance is being 85 * opened and closed elsewhere within the application. This mode is useful 86 * when the SPI bus is share by more than just the SPI flash device. 87 * 88 * If the SPI instance is to be managed internally by the NVSSPI25X driver, a SPI 89 * instance index and bit rate must be configured in the region's HWAttrs. 90 * If the same SPI instance is referenced by multiple flash regions 91 * the driver will ensure that SPI_open() is invoked only once, and that 92 * SPI_close() will only be invoked when all flash regions using the SPI 93 * instance have been closed. 94 * 95 * If the SPI bus that the SPI flash device is on is shared with other 96 * devices accessed by an application, then the SPI handle used to manage 97 * a SPI flash region can be provided in the region's HWAttrs "spiHandle" 98 * field. Keep in mind that the "spiHandle" field is a POINTER to a 99 * SPI Handle, NOT a SPI Handle. This allows the user to simply initialize 100 * this field with the name of the global variable used for the SPI handle. 101 * In this mode, the user MUST open the SPI instance prior to opening the NVS 102 * region instance so that the referenced spiHandle is valid. 103 * 104 * By default, the "spiHandle" field is set to NULL, indicating that the user 105 * expects the NVS driver to open and close the SPI instance internally using 106 * the 'spiIndex' and 'spiBitRate' provided in the HWAttrs. 107 * 108 * ## @anchor SPI_CS_MGMT SPI Flash Chip Select Management ## 109 * 110 * ### Option 1: NVSSPI25X Driver Manages Chip Select ### 111 * By default, the NVSSPI25X driver will assert and de-assert a GPIO 112 * driver managed pin to select the SPI flash device before and after 113 * each SPI transfer to and from the device. 114 * 115 * To enable this behavior, a valid GPIO driver instance index must be 116 * provided in the NVS region's [spiCsnGpioIndex] 117 * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) field of the 118 * NVSSPI25X_HWAttrs structure. The corresponding GPIO pin will be 119 * configured at runtime by the NVSSPI25X driver as "GPIO_CFG_OUT_STD" 120 * and assertion of this pin is assumed to be active LOW. 121 * 122 * ### Option 2: SPI Driver Manages Chip Select ### 123 * Some SPI peripherals can be configured to manage their own chip 124 * select. Setting the [spiCsnGpioIndex] 125 * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) field of the NVSSPI25X_HWAttrs 126 * structure to #NVSSPI25X_SPI_MANAGES_CS informs the NVSSPI25X driver 127 * that the SPI peripheral used by the NVS driver has been configured 128 * that way. 129 * 130 * ### Option 3: User Manages Chip Select ### 131 * Alternatively, the user can manage the assertion and de-assertion of 132 * the SPI flash chip select entirely themselves by providing implementations 133 * of the following 4 APIs in their application code: 134 * 135 * @code 136 * void NVSSPI25X_initSpiCs(NVS_Handle nvsHandle, uint16_t csId); 137 * @endcode 138 * - This function is invoked within the NVS_open() API and is where the 139 * user should do whatever is required to initialize the hardware 140 * used for asserting and de-assering the SPI chip select signal. 141 * - The 'nvsHandle` argument is the NVS handle associated with the 142 * corresponding NVS region. 143 * - The 'csId' argument passed to this API is a copy of the [spiCsnGpioIndex] 144 * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) 145 * field of the corresponding NVS region's NVSSPI25X_HWAttrs structure. 146 * 147 * @code 148 * void NVSSPI25X_deinitSpiCs(NVS_Handle nvsHandle, uint16_t csId); 149 * @endcode 150 * - This function is invoked within the NVS_close() API and is where the 151 * user should do whatever is required to de-initialize the hardware 152 * used for asserting and de-assering the SPI chip select signal. 153 * - The 'nvsHandle` argument is the NVS handle associated with the 154 * corresponding NVS region. 155 * - The 'csId' argument passed to this API is a copy of the [spiCsnGpioIndex] 156 * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) 157 * field of the corresponding NVS region's NVSSPI25X_HWAttrs structure. 158 * 159 * @code 160 * void NVSSPI25X_assertSpiCs(NVS_Handle nvsHandle, uint16_t csId); 161 * @endcode 162 * - This function is called PRIOR to every SPI transfer to and from the SPI 163 * flash device performed by the NVSSPI25X driver. The user code should 164 * perform the corresponding action required to select the SPI flash 165 * device to prepare for the SPI transfer. 166 * - The 'nvsHandle` argument is the NVS handle associated with the 167 * corresponding NVS region. 168 * - The 'csId' argument passed to this API is a copy of the [spiCsnGpioIndex] 169 * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) 170 * field of the corresponding NVS region's NVSSPI25X_HWAttrs structure. 171 * 172 * @code 173 * void NVSSPI25X_deassertSpiCs(NVS_Handle nvsHandle, uint16_t csId); 174 * @endcode 175 * - This function is called AFTER every SPI transfer to and from the SPI 176 * flash device performed by the NVSSPI25X driver. The user code should 177 * perform the corresponding action required to de-select the SPI flash 178 * device. 179 * following the SPI transfer. 180 * - The 'nvsHandle` argument is the NVS handle associated with the 181 * corresponding NVS region. 182 * - The 'csId' argument passed to this API is a copy of the [spiCsnGpioIndex] 183 * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) 184 * field of the corresponding NVS region's NVSSPI25X_HWAttrs structure. 185 * 186 * @warning All 4 of the above APIs must be provided by the user if this 187 * option is used, otherwise default internal implementations of the APIs 188 * will be called that will likely lead to application failure. 189 */ 190 191 #ifndef ti_drivers_nvs_NVSSPI25X__include 192 #define ti_drivers_nvs_NVSSPI25X__include 193 194 #include <stdint.h> 195 #include <stdbool.h> 196 197 #include <ti/drivers/SPI.h> 198 199 #if defined (__cplusplus) 200 extern "C" { 201 #endif 202 203 /*! 204 * @brief Command to perform mass erase of entire flash 205 * 206 * As this command can erase flash memory outside the region associated 207 * with the NVS_Handle passed to the control command, the user must 208 * carefully orchestrate the use of the command. 209 * 210 * Mass Erase is the only control command supported. 211 */ 212 #define NVSSPI25X_CMD_MASS_ERASE (NVS_CMD_RESERVED + 0) 213 214 /*! 215 * @brief Disable internal management of SPI chip select 216 * 217 * Some SPI peripherals can be configured to manage their own chip 218 * select. Setting the [spiCsnGpioIndex] 219 * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) field of the NVSSPI25X_HWAttrs 220 * structure to #NVSSPI25X_SPI_MANAGES_CS informs the NVSSPI25X driver 221 * that the SPI peripheral used by the NVS driver is configured 222 * to manage its own chip select signal. 223 */ 224 #define NVSSPI25X_SPI_MANAGES_CS ((uint16_t)(~0)) 225 226 /*! 227 * @internal @brief NVS function pointer table 228 * 229 * 'NVSSPI25X_fxnTable' is a fully populated function pointer table 230 * that can be referenced in the NVS_config[] array entries. 231 * 232 * Users can minimize their application code size by providing their 233 * own custom NVS function pointer table that contains only those APIs 234 * used by the application. 235 */ 236 extern const NVS_FxnTable NVSSPI25X_fxnTable; 237 238 /*! 239 * @brief NVSSPI25X attributes 240 * 241 * The 'regionBaseOffset' is the offset, in bytes, from the base of the 242 * SPI flash, of the flash region to be managed. 243 * 244 * The 'regionSize' must be an integer multiple of the flash sector size. 245 * 246 * The 'sectorSize' is SPI flash device specific. This parameter should 247 * correspond to the number of bytes erased when the 248 * 'SPIFLASH_SUBSECTOR_ERASE' (0x20) command is issued to the device. 249 * 250 * The 'verifyBuf' and 'verifyBufSize' parameters are used by the 251 * NVS_write() command when either 'NVS_WRITE_PRE_VERIFY' or 252 * 'NVS_WRITE_POST_VERIFY' functions are requested in the 'flags' 253 * argument. The 'verifyBuf' is used to successively read back portions 254 * of the flash to compare with the data being written to it. 255 * 256 * @code 257 * // 258 * // Only one region write operation is performed at a time 259 * // so a single verifyBuf can be shared by all the regions. 260 * // 261 * uint8_t verifyBuf[256]; 262 * 263 * NVSSPI25X_HWAttrs nvsSPIHWAttrs[2] = { 264 * // 265 * // region 0 is 1 flash sector in length. 266 * // 267 * { 268 * .regionBaseOffset = 0, 269 * .regionSize = 4096, 270 * .sectorSize = 4096, 271 * .verifyBuf = verifyBuf; 272 * .verifyBufSize = 256; 273 * .spiHandle = NULL, 274 * .spiIndex = 0, 275 * .spiBitRate = 40000000, 276 * .spiCsnGpioIndex = 12, 277 * }, 278 * // 279 * // region 1 is 3 flash sectors in length. 280 * // 281 * { 282 * .regionBaseOffset = 4096, 283 * .regionSize = 4096 * 3, 284 * .sectorSize = 4096, 285 * .verifyBuf = verifyBuf; // use shared verifyBuf 286 * .verifyBufSize = 256; 287 * .spiHandle = NULL, 288 * .spiIndex = 0, 289 * .spiBitRate = 40000000, 290 * .spiCsnGpioIndex = 12, 291 * } 292 * }; 293 * @endcode 294 */ 295 typedef struct 296 { 297 size_t regionBaseOffset; /*!< Offset from base of SPI flash */ 298 size_t regionSize; /*!< The size of the region in bytes */ 299 size_t sectorSize; /*!< Erase sector size */ 300 uint8_t *verifyBuf; /*!< Write Pre/Post verify buffer */ 301 size_t verifyBufSize; /*!< Write Pre/Post verify buffer size */ 302 SPI_Handle *spiHandle; /*!< ptr to SPI handle if provided by user. */ 303 uint16_t spiIndex; /*!< SPI instance index from Board file */ 304 uint32_t spiBitRate; /*!< SPI bit rate in Hz */ 305 /*! @brief SPI Flash Chip Select GPIO index 306 307 This field should be set to either an index within the 308 GPIO driver's GPIO_Config table, or to #NVSSPI25X_SPI_MANAGES_CS. 309 see [SPI Flash Chip Select Management] (@ref SPI_CS_MGMT) for more 310 details. 311 */ 312 uint16_t spiCsnGpioIndex; 313 /*! @brief External Flash Status Poll Delay 314 * 315 * This field determines how many microseconds the driver waits after 316 * querying the external flash status. Increasing this value can help 317 * mitigate CPU starvation if the external flash is busy for long periods 318 * of time, but may also result in increased latency. 319 */ 320 uint32_t statusPollDelayUs; 321 } NVSSPI25X_HWAttrs; 322 323 /* 324 * @brief NVSSPI25X Object 325 * 326 * The application must not access any member variables of this structure! 327 */ 328 typedef struct 329 { 330 bool opened; /* Has this region been opened */ 331 SPI_Handle spiHandle; 332 size_t sectorBaseMask; 333 } NVSSPI25X_Object; 334 335 /* 336 * @cond NODOC 337 * NVSSPI25X driver public APIs 338 */ 339 340 extern void NVSSPI25X_close(NVS_Handle handle); 341 extern int_fast16_t NVSSPI25X_control(NVS_Handle handle, uint_fast16_t cmd, 342 uintptr_t arg); 343 extern int_fast16_t NVSSPI25X_erase(NVS_Handle handle, size_t offset, 344 size_t size); 345 extern void NVSSPI25X_getAttrs(NVS_Handle handle, NVS_Attrs *attrs); 346 extern void NVSSPI25X_init(); 347 extern int_fast16_t NVSSPI25X_lock(NVS_Handle handle, uint32_t timeout); 348 extern NVS_Handle NVSSPI25X_open(uint_least8_t index, NVS_Params *params); 349 extern int_fast16_t NVSSPI25X_read(NVS_Handle handle, size_t offset, 350 void *buffer, size_t bufferSize); 351 extern void NVSSPI25X_unlock(NVS_Handle handle); 352 extern int_fast16_t NVSSPI25X_write(NVS_Handle handle, size_t offset, 353 void *buffer, size_t bufferSize, uint_fast16_t flags); 354 /* 355 * Weakly defined APIs that can be overridden by the user 356 */ 357 extern void NVSSPI25X_initSpiCs(NVS_Handle spiHandle, uint16_t csId); 358 extern void NVSSPI25X_deinitSpiCs(NVS_Handle spiHandle, uint16_t csId); 359 extern void NVSSPI25X_assertSpiCs(NVS_Handle spiHandle, uint16_t csId); 360 extern void NVSSPI25X_deassertSpiCs(NVS_Handle spiHandle, uint16_t csId); 361 362 /*! @endcond */ 363 364 #if defined (__cplusplus) 365 } 366 #endif /* defined (__cplusplus) */ 367 368 /** @}*/ 369 #endif /* ti_drivers_nvs_NVSSPI25X__include */ 370