| /**************************************************************************** |
| * boards/arm/at32/at32f437-mini/src/at32_w25.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 <stdbool.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <debug.h> |
| |
| #ifdef CONFIG_AT32_SPI1 |
| #include <nuttx/spi/spi.h> |
| #include <nuttx/mtd/mtd.h> |
| #include <nuttx/fs/smart.h> |
| #include <nuttx/mtd/configdata.h> |
| #endif |
| |
| #include "at32_spi.h" |
| |
| #include "at32f437-mini.h" |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /* Debug ********************************************************************/ |
| |
| /* Non-standard debug that may be enabled just for testing the watchdog |
| * timer |
| */ |
| |
| #define W25_SPI_PORT 1 |
| |
| /* Configuration ************************************************************/ |
| |
| /* Can't support the W25 device if it SPI1 or W25 support is not enabled */ |
| |
| #define HAVE_W25 1 |
| #if !defined(CONFIG_AT32_SPI1) || !defined(CONFIG_MTD_W25) |
| #undef HAVE_W25 |
| #endif |
| |
| /* Can't support W25 features if mountpoints are disabled */ |
| |
| #if defined(CONFIG_DISABLE_MOUNTPOINT) |
| #undef HAVE_W25 |
| #endif |
| |
| /* Can't support both FAT and SMARTFS */ |
| |
| #if defined(CONFIG_FS_FAT) && defined(CONFIG_FS_SMARTFS) |
| #warning "Can't support both FAT and SMARTFS -- using FAT" |
| #endif |
| |
| #define FLASH_PART_NAMES "w25qxx" |
| |
| #define FLASH_PART 1 |
| |
| #define FLASH_PART_LIST "4096, 4096, 4096" |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: at32_w25initialize |
| * |
| * Description: |
| * Initialize and register the W25 FLASH file system. |
| * |
| ****************************************************************************/ |
| |
| int at32_w25initialize(int minor) |
| { |
| int ret; |
| #ifdef HAVE_W25 |
| struct spi_dev_s *spi; |
| struct mtd_dev_s *mtd; |
| #if defined(CONFIG_MTD_PARTITION_NAMES) |
| const char *partname = FLASH_PART_NAMES; |
| #endif |
| |
| /* Get the SPI port */ |
| |
| spi = at32_spibus_initialize(W25_SPI_PORT); |
| if (!spi) |
| { |
| syslog(LOG_ERR, "ERROR: Failed to initialize SPI port %d\n", |
| W25_SPI_PORT); |
| return -ENODEV; |
| } |
| |
| /* Now bind the SPI interface to the W25 SPI FLASH driver */ |
| |
| mtd = w25_initialize(spi); |
| if (!mtd) |
| { |
| syslog(LOG_ERR, "ERROR: Failed to bind SPI port %d to the Winbond" |
| "W25 FLASH driver\n", |
| W25_SPI_PORT); |
| return -ENODEV; |
| } |
| |
| #ifndef CONFIG_FS_SMARTFS |
| /* And use the FTL layer to wrap the MTD driver as a block driver */ |
| |
| ret = ftl_initialize(minor, mtd); |
| if (ret < 0) |
| { |
| syslog(LOG_ERR, "ERROR: Initialize the FTL layer\n"); |
| return ret; |
| } |
| #else |
| /* Initialize to provide SMARTFS on the MTD interface */ |
| |
| #ifdef FLASH_PART |
| { |
| int partno; |
| int partsize; |
| int partoffset; |
| int partszbytes; |
| int erasesize; |
| const char *partstring = FLASH_PART_LIST; |
| const char *ptr; |
| struct mtd_dev_s *mtd_part; |
| char partref[16]; |
| struct mtd_geometry_s geo; |
| |
| /* Now create a partition on the FLASH device */ |
| |
| partno = 0; |
| ptr = partstring; |
| partoffset = 0; |
| |
| /* Get the geometry of the FLASH device */ |
| |
| ret = mtd->ioctl(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&geo)); |
| if (ret < 0) |
| { |
| syslog(LOG_ERR, "ERROR: mtd->ioctl failed: %d\n", ret); |
| return ret; |
| } |
| |
| /* Get the Flash erase size */ |
| |
| erasesize = geo.erasesize; |
| |
| while (*ptr != '\0') |
| { |
| /* Get the partition size */ |
| |
| partsize = atoi(ptr); |
| partszbytes = (partsize << 10); /* partsize is defined in KB */ |
| |
| /* Check if partition size is bigger then erase block */ |
| |
| if (partszbytes < erasesize) |
| { |
| syslog(LOG_ERR, |
| "ERROR: Partition size is lesser than erasesize!\n"); |
| return -1; |
| } |
| |
| /* Check if partition size is multiple of erase block */ |
| |
| if ((partszbytes % erasesize) != 0) |
| { |
| syslog(LOG_ERR, |
| "ERROR: Partition size isn't multiple of erasesize!\n"); |
| return -1; |
| } |
| |
| mtd_part = mtd_partition(mtd, partoffset, partszbytes / erasesize); |
| partoffset += partszbytes / erasesize; |
| |
| #ifdef FLASH_CONFIG_PART |
| /* Test if this is the config partition */ |
| |
| if (FLASH_CONFIG_PART_NUMBER == partno) |
| { |
| /* Register the partition as the config device */ |
| |
| mtdconfig_register(mtd_part); |
| } |
| else |
| #endif |
| { |
| /* Now initialize a SMART Flash block device and bind it |
| * to the MTD device. |
| */ |
| |
| #if defined(CONFIG_MTD_SMART) && defined(CONFIG_FS_SMARTFS) |
| snprintf(partref, sizeof(partref), "p%d", partno); |
| smart_initialize(W25QXX_FLASH_MINOR, |
| mtd_part, partref); |
| #endif |
| } |
| |
| /* Set the partition name */ |
| |
| #if defined(CONFIG_MTD_PARTITION_NAMES) |
| if (!mtd_part) |
| { |
| syslog(LOG_ERR, "Error: failed to create partition %s\n", |
| partname); |
| return -1; |
| } |
| |
| mtd_setpartitionname(mtd_part, partname); |
| |
| /* Now skip to next name. We don't need to split the string here |
| * because the MTD partition logic will only display names up to |
| * the comma, thus allowing us to use a single static name |
| * in the code. |
| */ |
| |
| while (*partname != ',' && *partname != '\0') |
| { |
| /* Skip to next ',' */ |
| |
| partname++; |
| } |
| |
| if (*partname == ',') |
| { |
| partname++; |
| } |
| #endif |
| |
| /* Update the pointer to point to the next size in the list */ |
| |
| while ((*ptr >= '0') && (*ptr <= '9')) |
| { |
| ptr++; |
| } |
| |
| if (*ptr == ',') |
| { |
| ptr++; |
| } |
| |
| /* Increment the part number */ |
| |
| partno++; |
| } |
| } |
| |
| #else /* CONFIG_FLASH_PART */ |
| |
| /* Configure the device with no partition support */ |
| |
| smart_initialize(W25QXX_FLASH_MINOR, mtd, NULL); |
| |
| #endif /* CONFIG_FLASH_PART */ |
| #endif /* CONFIG_FS_SMARTFS */ |
| #endif /* HAVE_W25 */ |
| |
| return OK; |
| } |