| /**************************************************************************** |
| * arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <stdint.h> |
| #include <assert.h> |
| #include <debug.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <inttypes.h> |
| #include <errno.h> |
| |
| #include <nuttx/arch.h> |
| #include <nuttx/init.h> |
| #include <nuttx/mutex.h> |
| #include <nuttx/mtd/mtd.h> |
| |
| #include "hardware/esp32s3_soc.h" |
| #include "hardware/esp32s3_cache_memory.h" |
| |
| #include "esp_attr.h" |
| #include "esp32s3_spiflash.h" |
| #include "esp32s3_spiram.h" |
| |
| #include "rom/esp32s3_spiflash.h" |
| #include "esp32s3_spiflash_mtd.h" |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| #define MTD_BLK_SIZE CONFIG_ESP32S3_SPIFLASH_MTD_BLKSIZE |
| #define MTD_ERASE_SIZE 4096 |
| #define MTD_ERASED_STATE (0xff) |
| |
| #define MTD2PRIV(_dev) ((struct esp32s3_mtd_dev_s *)_dev) |
| #define MTD_SIZE(_priv) ((*(_priv)->data)->chip.chip_size) |
| #define MTD_BLK2SIZE(_priv, _b) (MTD_BLK_SIZE * (_b)) |
| #define MTD_SIZE2BLK(_priv, _s) ((_s) / MTD_BLK_SIZE) |
| |
| #define SPI_FLASH_ENCRYPT_UNIT_SIZE (64) |
| #define SPI_FLASH_ENCRYPT_MIN_SIZE (16) |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| /* SPI flash work operation code */ |
| |
| enum spiflash_op_code_e |
| { |
| SPIFLASH_OP_CODE_WRITE = 0, |
| SPIFLASH_OP_CODE_READ, |
| SPIFLASH_OP_CODE_ERASE, |
| SPIFLASH_OP_CODE_SET_BANK, |
| SPIFLASH_OP_CODE_ENCRYPT_READ, |
| SPIFLASH_OP_CODE_ENCRYPT_WRITE |
| }; |
| #endif |
| |
| /* ESP32-S3 SPI Flash device private data */ |
| |
| struct esp32s3_mtd_dev_s |
| { |
| struct mtd_dev_s mtd; |
| |
| /* SPI Flash data */ |
| |
| esp_rom_spiflash_legacy_data_t **data; |
| }; |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| /* SPI flash work operation arguments */ |
| |
| struct spiflash_work_arg |
| { |
| enum spiflash_op_code_e op_code; |
| |
| struct |
| { |
| uint32_t addr; |
| uint8_t *buffer; |
| uint32_t size; |
| uint32_t paddr; |
| } op_arg; |
| |
| volatile int ret; |
| |
| sem_t sem; |
| }; |
| #endif |
| |
| /**************************************************************************** |
| * Private Functions Prototypes |
| ****************************************************************************/ |
| |
| /* MTD driver methods */ |
| |
| static int esp32s3_erase(struct mtd_dev_s *dev, off_t startblock, |
| size_t nblocks); |
| static ssize_t esp32s3_read(struct mtd_dev_s *dev, off_t offset, |
| size_t nbytes, uint8_t *buffer); |
| static ssize_t esp32s3_read_decrypt(struct mtd_dev_s *dev, |
| off_t offset, |
| size_t nbytes, |
| uint8_t *buffer); |
| static ssize_t esp32s3_bread(struct mtd_dev_s *dev, off_t startblock, |
| size_t nblocks, uint8_t *buffer); |
| static ssize_t esp32s3_bread_decrypt(struct mtd_dev_s *dev, |
| off_t startblock, |
| size_t nblocks, |
| uint8_t *buffer); |
| static ssize_t esp32s3_write(struct mtd_dev_s *dev, off_t offset, |
| size_t nbytes, const uint8_t *buffer); |
| static ssize_t esp32s3_bwrite(struct mtd_dev_s *dev, off_t startblock, |
| size_t nblocks, const uint8_t *buffer); |
| static int esp32s3_writedata_encrypt(struct mtd_dev_s *dev, off_t offset, |
| uint32_t size, const uint8_t *buffer); |
| static ssize_t esp32s3_write_encrypt(struct mtd_dev_s *dev, off_t offset, |
| size_t nbytes, const uint8_t *buffer); |
| static ssize_t esp32s3_bwrite_encrypt(struct mtd_dev_s *dev, |
| off_t startblock, |
| size_t nblocks, |
| const uint8_t *buffer); |
| static int esp32s3_ioctl(struct mtd_dev_s *dev, int cmd, |
| unsigned long arg); |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| static inline bool IRAM_ATTR stack_is_psram(void); |
| static void esp32s3_spiflash_work(void *arg); |
| static int esp32s3_async_op(enum spiflash_op_code_e opcode, |
| uint32_t addr, |
| const uint8_t *buffer, |
| uint32_t size, |
| uint32_t paddr); |
| #endif |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| static const struct esp32s3_mtd_dev_s g_esp32s3_spiflash = |
| { |
| .mtd = |
| { |
| .erase = esp32s3_erase, |
| .bread = esp32s3_bread, |
| .bwrite = esp32s3_bwrite, |
| .read = esp32s3_read, |
| .ioctl = esp32s3_ioctl, |
| #ifdef CONFIG_MTD_BYTE_WRITE |
| .write = esp32s3_write, |
| #endif |
| .name = "esp32s3_spiflash" |
| }, |
| .data = (esp_rom_spiflash_legacy_data_t **) |
| (&rom_spiflash_legacy_data), |
| }; |
| |
| static const struct esp32s3_mtd_dev_s g_esp32s3_spiflash_encrypt = |
| { |
| .mtd = |
| { |
| .erase = esp32s3_erase, |
| .bread = esp32s3_bread_decrypt, |
| .bwrite = esp32s3_bwrite_encrypt, |
| .read = esp32s3_read_decrypt, |
| .ioctl = esp32s3_ioctl, |
| #ifdef CONFIG_MTD_BYTE_WRITE |
| .write = esp32s3_write_encrypt, |
| #endif |
| .name = "esp32s3_spiflash_encrypt" |
| }, |
| .data = (esp_rom_spiflash_legacy_data_t **) |
| (&rom_spiflash_legacy_data), |
| }; |
| |
| /* Ensure exclusive access to the driver */ |
| |
| static mutex_t g_lock = NXMUTEX_INITIALIZER; |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| static struct work_s g_work; |
| #endif |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: stack_is_psram |
| * |
| * Description: |
| * Check if current task's stack space is in PSRAM. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * true if it is in PSRAM or false if not. |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| static inline bool IRAM_ATTR stack_is_psram(void) |
| { |
| void *sp = (void *)up_getsp(); |
| |
| return esp32s3_ptr_extram(sp); |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: esp32s3_spiflash_work |
| * |
| * Description: |
| * Do SPI Flash operation, cache result and send semaphore to wake up |
| * blocked task. |
| * |
| * Input Parameters: |
| * arg - Reference to SPI flash work arguments structure (cast to void*) |
| * |
| * Returned Value: |
| * None. |
| * |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| static void esp32s3_spiflash_work(void *arg) |
| { |
| struct spiflash_work_arg *work_arg = (struct spiflash_work_arg *)arg; |
| |
| if (work_arg->op_code == SPIFLASH_OP_CODE_WRITE) |
| { |
| work_arg->ret = spi_flash_write(work_arg->op_arg.addr, |
| work_arg->op_arg.buffer, |
| work_arg->op_arg.size); |
| } |
| else if (work_arg->op_code == SPIFLASH_OP_CODE_READ) |
| { |
| work_arg->ret = spi_flash_read(work_arg->op_arg.addr, |
| work_arg->op_arg.buffer, |
| work_arg->op_arg.size); |
| } |
| else if (work_arg->op_code == SPIFLASH_OP_CODE_ERASE) |
| { |
| work_arg->ret = spi_flash_erase_range(work_arg->op_arg.addr, |
| work_arg->op_arg.size); |
| } |
| else if (work_arg->op_code == SPIFLASH_OP_CODE_SET_BANK) |
| { |
| work_arg->ret = cache_dbus_mmu_map(work_arg->op_arg.addr, |
| work_arg->op_arg.paddr, |
| work_arg->op_arg.size); |
| } |
| else if (work_arg->op_code == SPIFLASH_OP_CODE_ENCRYPT_READ) |
| { |
| work_arg->ret = spi_flash_read_encrypted(work_arg->op_arg.addr, |
| work_arg->op_arg.buffer, |
| work_arg->op_arg.size); |
| } |
| else if (work_arg->op_code == SPIFLASH_OP_CODE_ENCRYPT_WRITE) |
| { |
| work_arg->ret = spi_flash_write_encrypted(work_arg->op_arg.addr, |
| work_arg->op_arg.buffer, |
| work_arg->op_arg.size); |
| } |
| else |
| { |
| ferr("ERROR: op_code=%d is not supported\n", work_arg->op_code); |
| } |
| |
| nxsem_post(&work_arg->sem); |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_async_op |
| * |
| * Description: |
| * Send operation code and arguments to workqueue so that workqueue do SPI |
| * Flash operation actually. |
| * |
| * Input Parameters: |
| * opcode - SPI flash work operation code |
| * addr - target address |
| * buffer - data buffer pointer |
| * size - data number |
| * |
| * Returned Value: |
| * 0 if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static int esp32s3_async_op(enum spiflash_op_code_e opcode, |
| uint32_t addr, |
| const uint8_t *buffer, |
| uint32_t size, |
| uint32_t paddr) |
| { |
| int ret; |
| struct spiflash_work_arg work_arg = |
| { |
| .op_code = opcode, |
| .op_arg = |
| { |
| .addr = addr, |
| .buffer = (uint8_t *)buffer, |
| .size = size, |
| .paddr = paddr, |
| }, |
| .sem = NXSEM_INITIALIZER(0, 0) |
| }; |
| |
| ret = work_queue(LPWORK, &g_work, esp32s3_spiflash_work, &work_arg, 0); |
| if (ret == 0) |
| { |
| nxsem_wait(&work_arg.sem); |
| ret = work_arg.ret; |
| } |
| |
| return ret; |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: esp32s3_erase |
| * |
| * Description: |
| * Erase SPI Flash designated sectors. |
| * |
| * Input Parameters: |
| * dev - MTD device data |
| * startblock - start block number, it is not equal to SPI Flash's block |
| * nblocks - Number of blocks |
| * |
| * Returned Value: |
| * Erased blocks if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static int esp32s3_erase(struct mtd_dev_s *dev, off_t startblock, |
| size_t nblocks) |
| { |
| ssize_t ret; |
| uint32_t offset = startblock * MTD_ERASE_SIZE; |
| uint32_t nbytes = nblocks * MTD_ERASE_SIZE; |
| struct esp32s3_mtd_dev_s *priv = (struct esp32s3_mtd_dev_s *)dev; |
| |
| if ((offset > MTD_SIZE(priv)) || ((offset + nbytes) > MTD_SIZE(priv))) |
| { |
| return -EINVAL; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s(%p, 0x%" PRIxOFF ", %zu)\n", __func__, dev, startblock, nblocks); |
| |
| finfo("spi_flash_erase_range(0x%x, %d)\n", offset, nbytes); |
| #endif |
| |
| ret = nxmutex_lock(&g_lock); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| if (stack_is_psram()) |
| { |
| ret = esp32s3_async_op(SPIFLASH_OP_CODE_ERASE, offset, NULL, |
| nbytes, 0); |
| } |
| else |
| #endif |
| { |
| ret = spi_flash_erase_range(offset, nbytes); |
| } |
| |
| nxmutex_unlock(&g_lock); |
| if (ret == OK) |
| { |
| ret = nblocks; |
| } |
| else |
| { |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("Failed to erase the flash range!\n"); |
| #endif |
| ret = -1; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s()=%d\n", __func__, ret); |
| #endif |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_read |
| * |
| * Description: |
| * Read data from SPI Flash at designated address. |
| * |
| * Input Parameters: |
| * dev - MTD device data |
| * offset - target address offset |
| * nbytes - data number |
| * buffer - data buffer pointer |
| * |
| * Returned Value: |
| * Read data bytes if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static ssize_t esp32s3_read(struct mtd_dev_s *dev, off_t offset, |
| size_t nbytes, uint8_t *buffer) |
| { |
| ssize_t ret; |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s(%p, 0x%" PRIxOFF ", %zu, %p)\n", |
| __func__, dev, offset, nbytes, buffer); |
| |
| finfo("spi_flash_read(0x%" PRIxOFF ", %p, %zu)\n", offset, buffer, nbytes); |
| #endif |
| |
| /* Acquire the mutex. */ |
| |
| ret = nxmutex_lock(&g_lock); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| if (stack_is_psram()) |
| { |
| ret = esp32s3_async_op(SPIFLASH_OP_CODE_READ, offset, |
| buffer, nbytes, 0); |
| } |
| else |
| #endif |
| { |
| ret = spi_flash_read(offset, buffer, nbytes); |
| } |
| |
| nxmutex_unlock(&g_lock); |
| if (ret == OK) |
| { |
| ret = nbytes; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s()=%d\n", __func__, ret); |
| #endif |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_bread |
| * |
| * Description: |
| * Read data from designated blocks. |
| * |
| * Input Parameters: |
| * dev - MTD device data |
| * startblock - start block number, it is not equal to SPI Flash's block |
| * nblocks - blocks number |
| * buffer - data buffer pointer |
| * |
| * Returned Value: |
| * Read block number if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static ssize_t esp32s3_bread(struct mtd_dev_s *dev, off_t startblock, |
| size_t nblocks, uint8_t *buffer) |
| { |
| ssize_t ret; |
| uint32_t addr = startblock * MTD_BLK_SIZE; |
| uint32_t size = nblocks * MTD_BLK_SIZE; |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s(%p, 0x%" PRIxOFF ", %zu, %p)\n", |
| __func__, dev, startblock, nblocks, buffer); |
| #endif |
| |
| ret = esp32s3_read(dev, addr, size, buffer); |
| if (ret == size) |
| { |
| ret = nblocks; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s()=%d\n", __func__, ret); |
| #endif |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_read_decrypt |
| * |
| * Description: |
| * Read encrypted data and decrypt automatically from SPI Flash |
| * at designated address. |
| * |
| * Input Parameters: |
| * dev - MTD device data |
| * offset - target address offset |
| * nbytes - data number |
| * buffer - data buffer pointer |
| * |
| * Returned Value: |
| * Read data bytes if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static ssize_t esp32s3_read_decrypt(struct mtd_dev_s *dev, |
| off_t offset, |
| size_t nbytes, |
| uint8_t *buffer) |
| { |
| ssize_t ret; |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s(%p, 0x%" PRIxOFF ", %zu, %p)\n", |
| __func__, dev, offset, nbytes, buffer); |
| |
| finfo("spi_flash_read_encrypted(0x%" PRIxOFF ", %p, %zu)\n", |
| offset, buffer, nbytes); |
| #endif |
| |
| /* Acquire the mutex. */ |
| |
| ret = nxmutex_lock(&g_lock); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| if (stack_is_psram()) |
| { |
| ret = esp32s3_async_op(SPIFLASH_OP_CODE_ENCRYPT_READ, offset, |
| buffer, nbytes, 0); |
| } |
| else |
| #endif |
| { |
| ret = spi_flash_read_encrypted(offset, buffer, nbytes); |
| } |
| |
| nxmutex_unlock(&g_lock); |
| if (ret == OK) |
| { |
| ret = nbytes; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s()=%d\n", __func__, ret); |
| #endif |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_bread_decrypt |
| * |
| * Description: |
| * Read encrypted data and decrypt automatically from designated blocks. |
| * |
| * Input Parameters: |
| * dev - MTD device data |
| * startblock - start block number, it is not equal to SPI Flash's block |
| * nblocks - blocks number |
| * buffer - data buffer pointer |
| * |
| * Returned Value: |
| * Read block number if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static ssize_t esp32s3_bread_decrypt(struct mtd_dev_s *dev, |
| off_t startblock, |
| size_t nblocks, |
| uint8_t *buffer) |
| { |
| ssize_t ret; |
| uint32_t addr = startblock * MTD_BLK_SIZE; |
| uint32_t size = nblocks * MTD_BLK_SIZE; |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s(%p, 0x%" PRIxOFF ", %zu, %p)\n", |
| __func__, dev, startblock, nblocks, buffer); |
| #endif |
| |
| ret = esp32s3_read_decrypt(dev, addr, size, buffer); |
| if (ret == size) |
| { |
| ret = nblocks; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s()=%d\n", __func__, ret); |
| #endif |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_writedata_encrypt |
| * |
| * Description: |
| * Write plaintext data to SPI Flash at designated address by SPI Flash |
| * hardware encryption, and written data in SPI Flash is ciphertext. |
| * |
| * Input Parameters: |
| * dev - MTD device data |
| * offset - target address offset, must be 32Bytes-aligned |
| * size - data number, must be 32Bytes-aligned |
| * buffer - data buffer pointer |
| * |
| * Returned Value: |
| * 0 if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static int esp32s3_writedata_encrypt(struct mtd_dev_s *dev, off_t offset, |
| uint32_t size, const uint8_t *buffer) |
| { |
| ssize_t ret; |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s(%p, 0x%" PRIxOFF ", %zu, %p)\n", __func__, dev, offset, |
| size, buffer); |
| #endif |
| |
| DEBUGASSERT((offset % SPI_FLASH_ENCRYPT_MIN_SIZE) == 0); |
| DEBUGASSERT((size % SPI_FLASH_ENCRYPT_MIN_SIZE) == 0); |
| ret = nxmutex_lock(&g_lock); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| if (stack_is_psram()) |
| { |
| ret = esp32s3_async_op(SPIFLASH_OP_CODE_ENCRYPT_WRITE, offset, |
| buffer, size, 0); |
| } |
| else |
| #endif |
| { |
| ret = spi_flash_write_encrypted(offset, buffer, size); |
| } |
| |
| nxmutex_unlock(&g_lock); |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s()=%d\n", __func__, ret); |
| #endif |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_write_encrypt |
| * |
| * Description: |
| * Write data to SPI Flash at designated address by SPI Flash hardware |
| * encryption. |
| * |
| * Input Parameters: |
| * dev - MTD device data |
| * offset - target address offset, must be 16Bytes-aligned |
| * nbytes - data number, must be 16Bytes-aligned |
| * buffer - data buffer pointer |
| * |
| * Returned Value: |
| * Writen bytes if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static ssize_t esp32s3_write_encrypt(struct mtd_dev_s *dev, off_t offset, |
| size_t nbytes, const uint8_t *buffer) |
| { |
| ssize_t ret; |
| size_t n; |
| off_t addr; |
| size_t wbytes; |
| uint32_t step; |
| uint8_t enc_buf[SPI_FLASH_ENCRYPT_UNIT_SIZE]; |
| |
| if ((offset % SPI_FLASH_ENCRYPT_MIN_SIZE) || |
| (nbytes % SPI_FLASH_ENCRYPT_MIN_SIZE)) |
| { |
| return -EINVAL; |
| } |
| else if (nbytes == 0) |
| { |
| return 0; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, offset, nbytes, buffer); |
| #endif |
| |
| for (n = 0; n < nbytes; n += step) |
| { |
| /* The temporary buffer need to be seperated into |
| * 16-bytes, 32-bytes, 64-bytes(if supported). |
| */ |
| |
| addr = offset + n; |
| if ((addr % 64) == 0 && (nbytes - n) >= 64) |
| { |
| wbytes = 64; |
| } |
| else if ((addr % 32) == 0 && (nbytes - n) >= 32) |
| { |
| wbytes = 32; |
| } |
| else |
| { |
| wbytes = 16; |
| } |
| |
| memcpy(enc_buf, buffer + n, wbytes); |
| step = wbytes; |
| ret = esp32s3_writedata_encrypt(dev, addr, wbytes, enc_buf); |
| if (ret < 0) |
| { |
| break; |
| } |
| } |
| |
| if (ret >= 0) |
| { |
| ret = nbytes; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("esp32s3_write_encrypt()=%d\n", ret); |
| #endif |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_write |
| * |
| * Description: |
| * write data to SPI Flash at designated address. |
| * |
| * Input Parameters: |
| * dev - MTD device data |
| * offset - target address offset |
| * nbytes - data number |
| * buffer - data buffer pointer |
| * |
| * Returned Value: |
| * Writen bytes if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static ssize_t esp32s3_write(struct mtd_dev_s *dev, off_t offset, |
| size_t nbytes, const uint8_t *buffer) |
| { |
| ssize_t ret; |
| struct esp32s3_mtd_dev_s *priv = (struct esp32s3_mtd_dev_s *)dev; |
| |
| ASSERT(buffer); |
| |
| if ((offset > MTD_SIZE(priv)) || ((offset + nbytes) > MTD_SIZE(priv))) |
| { |
| return -EINVAL; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s(%p, 0x%" PRIxOFF ", %zu, %p)\n", |
| __func__, dev, offset, nbytes, buffer); |
| |
| finfo("spi_flash_write(0x%" PRIxOFF ", %p, %zu)\n", |
| offset, buffer, nbytes); |
| #endif |
| |
| /* Acquire the mutex. */ |
| |
| ret = nxmutex_lock(&g_lock); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| if (stack_is_psram()) |
| { |
| ret = esp32s3_async_op(SPIFLASH_OP_CODE_WRITE, offset, |
| buffer, nbytes, 0); |
| } |
| else |
| #endif |
| { |
| ret = spi_flash_write(offset, buffer, nbytes); |
| } |
| |
| nxmutex_unlock(&g_lock); |
| if (ret == OK) |
| { |
| ret = nbytes; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s()=%d\n", __func__, ret); |
| #endif |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_bwrite_encrypt |
| * |
| * Description: |
| * Write data to designated blocks by SPI Flash hardware encryption. |
| * |
| * Input Parameters: |
| * dev - MTD device data |
| * startblock - start MTD block number, |
| * it is not equal to SPI Flash's block |
| * nblocks - blocks number |
| * buffer - data buffer pointer |
| * |
| * Returned Value: |
| * Writen block number if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static ssize_t esp32s3_bwrite_encrypt(struct mtd_dev_s *dev, |
| off_t startblock, |
| size_t nblocks, |
| const uint8_t *buffer) |
| { |
| ssize_t ret; |
| uint32_t addr = startblock * MTD_BLK_SIZE; |
| uint32_t size = nblocks * MTD_BLK_SIZE; |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s(%p, 0x%" PRIxOFF ", %zu, %p)\n", __func__, dev, startblock, |
| nblocks, buffer); |
| |
| finfo("spi_flash_write_encrypted(0x%x, %p, %" PRIu32 ")\n", |
| addr, buffer, size); |
| #endif |
| |
| ret = nxmutex_lock(&g_lock); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| if (stack_is_psram()) |
| { |
| ret = esp32s3_async_op(SPIFLASH_OP_CODE_ENCRYPT_WRITE, addr, |
| buffer, size, 0); |
| } |
| else |
| #endif |
| { |
| ret = spi_flash_write_encrypted(addr, buffer, size); |
| } |
| |
| nxmutex_unlock(&g_lock); |
| if (ret == OK) |
| { |
| ret = nblocks; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s()=%d\n", __func__, ret); |
| #endif |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_bwrite |
| * |
| * Description: |
| * Write data to designated blocks. |
| * |
| * Input Parameters: |
| * dev - MTD device data |
| * startblock - start MTD block number, |
| * it is not equal to SPI Flash's block |
| * nblocks - blocks number |
| * buffer - data buffer pointer |
| * |
| * Returned Value: |
| * Writen block number if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static ssize_t esp32s3_bwrite(struct mtd_dev_s *dev, off_t startblock, |
| size_t nblocks, const uint8_t *buffer) |
| { |
| ssize_t ret; |
| uint32_t addr = startblock * MTD_BLK_SIZE; |
| uint32_t size = nblocks * MTD_BLK_SIZE; |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s(%p, 0x%" PRIxOFF ", %zu, %p)\n", __func__, dev, startblock, |
| nblocks, buffer); |
| #endif |
| |
| ret = esp32s3_write(dev, addr, size, buffer); |
| if (ret == size) |
| { |
| ret = nblocks; |
| } |
| |
| #ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG |
| finfo("%s()=%d\n", __func__, ret); |
| #endif |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_ioctl |
| * |
| * Description: |
| * Set/Get option to/from ESP32-S3 SPI Flash MTD device data. |
| * |
| * Input Parameters: |
| * dev - ESP32-S3 MTD device data |
| * cmd - operation command |
| * arg - operation argument |
| * |
| * Returned Value: |
| * 0 if success or a negative value if fail. |
| * |
| ****************************************************************************/ |
| |
| static int esp32s3_ioctl(struct mtd_dev_s *dev, int cmd, |
| unsigned long arg) |
| { |
| int ret = OK; |
| finfo("cmd: %d\n", cmd); |
| |
| switch (cmd) |
| { |
| case MTDIOC_GEOMETRY: |
| { |
| struct esp32s3_mtd_dev_s *priv = (struct esp32s3_mtd_dev_s *)dev; |
| struct mtd_geometry_s *geo = (struct mtd_geometry_s *)arg; |
| if (geo) |
| { |
| memset(geo, 0, sizeof(*geo)); |
| |
| geo->blocksize = MTD_BLK_SIZE; |
| geo->erasesize = MTD_ERASE_SIZE; |
| geo->neraseblocks = MTD_SIZE(priv) / MTD_ERASE_SIZE; |
| ret = OK; |
| |
| finfo("blocksize: %" PRId32 " erasesize: %" PRId32 \ |
| " neraseblocks: %" PRId32 "\n", |
| geo->blocksize, geo->erasesize, geo->neraseblocks); |
| } |
| } |
| break; |
| |
| case BIOC_PARTINFO: |
| { |
| struct esp32s3_mtd_dev_s *priv = (struct esp32s3_mtd_dev_s *)dev; |
| struct partition_info_s *info = (struct partition_info_s *)arg; |
| if (info != NULL) |
| { |
| info->numsectors = MTD_SIZE(priv) / MTD_BLK_SIZE; |
| info->sectorsize = MTD_BLK_SIZE; |
| info->startsector = 0; |
| info->parent[0] = '\0'; |
| } |
| } |
| break; |
| |
| case MTDIOC_ERASESTATE: |
| { |
| uint8_t *result = (uint8_t *)arg; |
| *result = MTD_ERASED_STATE; |
| |
| ret = OK; |
| } |
| break; |
| |
| default: |
| ret = -ENOTTY; |
| break; |
| } |
| |
| finfo("return %d\n", ret); |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: esp32s3_set_bank |
| * |
| * Description: |
| * Set Ext-SRAM-Cache mmu mapping. |
| * |
| * Input Parameters: |
| * virt_bank - Beginning of the virtual bank |
| * phys_bank - Beginning of the physical bank |
| * ct - Number of banks |
| * |
| * Returned Value: |
| * None. |
| * |
| ****************************************************************************/ |
| |
| void esp32s3_set_bank(int virt_bank, int phys_bank, int ct) |
| { |
| int ret; |
| uint32_t vaddr = SOC_EXTRAM_DATA_LOW + MMU_PAGE_SIZE * virt_bank; |
| uint32_t paddr = phys_bank * MMU_PAGE_SIZE; |
| #ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK |
| if (stack_is_psram()) |
| { |
| ret = esp32s3_async_op(SPIFLASH_OP_CODE_SET_BANK, vaddr, NULL, ct, |
| paddr); |
| } |
| else |
| #endif |
| { |
| ret = cache_dbus_mmu_map(vaddr, paddr, ct); |
| } |
| |
| DEBUGASSERT(ret == 0); |
| UNUSED(ret); |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_spiflash_alloc_mtdpart |
| * |
| * Description: |
| * Allocate an MTD partition from the ESP32-S3 SPI Flash. |
| * |
| * Input Parameters: |
| * mtd_offset - MTD Partition offset from the base address in SPI Flash. |
| * mtd_size - Size for the MTD partition. |
| * encrypted - Flag indicating whether the newly allocated partition will |
| * have its content encrypted. |
| * |
| * Returned Value: |
| * ESP32-S3 SPI Flash MTD data pointer if success or NULL if fail. |
| * |
| ****************************************************************************/ |
| |
| struct mtd_dev_s *esp32s3_spiflash_alloc_mtdpart(uint32_t mtd_offset, |
| uint32_t mtd_size, |
| bool encrypted) |
| { |
| const struct esp32s3_mtd_dev_s *priv; |
| const esp_rom_spiflash_chip_t *chip; |
| struct mtd_dev_s *mtd_part; |
| uint32_t blocks; |
| uint32_t startblock; |
| uint32_t size; |
| |
| if (encrypted) |
| { |
| priv = &g_esp32s3_spiflash_encrypt; |
| } |
| else |
| { |
| priv = &g_esp32s3_spiflash; |
| } |
| |
| chip = &(*priv->data)->chip; |
| |
| finfo("ESP32-S3 SPI Flash information:\n"); |
| finfo("\tID = 0x%" PRIx32 "\n", chip->device_id); |
| finfo("\tStatus mask = 0x%" PRIx32 "\n", chip->status_mask); |
| finfo("\tChip size = %" PRId32 " KB\n", chip->chip_size / 1024); |
| finfo("\tPage size = %" PRId32 " B\n", chip->page_size); |
| finfo("\tSector size = %" PRId32 " KB\n", chip->sector_size / 1024); |
| finfo("\tBlock size = %" PRId32 " KB\n", chip->block_size / 1024); |
| |
| ASSERT((mtd_offset + mtd_size) <= chip->chip_size); |
| ASSERT((mtd_offset % chip->sector_size) == 0); |
| ASSERT((mtd_size % chip->sector_size) == 0); |
| |
| if (mtd_size == 0) |
| { |
| size = chip->chip_size - mtd_offset; |
| } |
| else |
| { |
| size = mtd_size; |
| } |
| |
| finfo("\tMTD offset = 0x%" PRIx32 "\n", mtd_offset); |
| finfo("\tMTD size = 0x%" PRIx32 "\n", size); |
| |
| startblock = MTD_SIZE2BLK(priv, mtd_offset); |
| blocks = MTD_SIZE2BLK(priv, size); |
| |
| mtd_part = mtd_partition((struct mtd_dev_s *)&priv->mtd, startblock, |
| blocks); |
| if (!mtd_part) |
| { |
| ferr("ERROR: Failed to create MTD partition\n"); |
| return NULL; |
| } |
| |
| return mtd_part; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_spiflash_mtd |
| * |
| * Description: |
| * Get SPI Flash MTD. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * ESP32-S3 SPI Flash MTD pointer. |
| * |
| ****************************************************************************/ |
| |
| struct mtd_dev_s *esp32s3_spiflash_mtd(void) |
| { |
| struct esp32s3_mtd_dev_s *priv = |
| (struct esp32s3_mtd_dev_s *)&g_esp32s3_spiflash; |
| |
| return &priv->mtd; |
| } |
| |
| /**************************************************************************** |
| * Name: esp32s3_spiflash_encrypt_mtd |
| * |
| * Description: |
| * Get SPI Flash encryption MTD. |
| * |
| * Input Parameters: |
| * None |
| * |
| * Returned Value: |
| * SPI Flash encryption MTD pointer. |
| * |
| ****************************************************************************/ |
| |
| struct mtd_dev_s *esp32s3_spiflash_encrypt_mtd(void) |
| { |
| struct esp32s3_mtd_dev_s *priv = |
| (struct esp32s3_mtd_dev_s *)&g_esp32s3_spiflash_encrypt; |
| |
| return &priv->mtd; |
| } |