@@ -171,6 +171,7 @@
#include "yaffs_mtdif.h"
#include "yaffs_mtdif1.h"
#include "yaffs_mtdif2.h"
+#include "yaffs_mtdif2_nor.h"
unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
@@ -2913,7 +2914,8 @@
return NULL;
}
/* Check it's NAND */
- if (mtd->type != MTD_NANDFLASH) {
+ if (mtd->type != MTD_NANDFLASH && mtd->type != MTD_NORFLASH) {
T(YAFFS_TRACE_ALWAYS,
(TSTR("yaffs: MTD device is not NAND it's type %d\n"),
mtd->type));
@@ -2954,6 +2956,11 @@
yaffs_version = 2;
}
+ if (mtd->type == MTD_NORFLASH) {
+ yaffs_version = 2;
+ }
+
/* Added NCB 26/5/2006 for completeness */
if (yaffs_version == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
T(YAFFS_TRACE_ALWAYS,
@@ -2963,7 +2970,18 @@
#endif
- if (yaffs_version == 2) {
+ if (yaffs_version == 2 && mtd->type == MTD_NORFLASH) {
+ /* Check for version 2 style functions */
+ if (!mtd->_erase ||
+ !mtd->_read ||
+ !mtd->_write) {
+ T(YAFFS_TRACE_ALWAYS,
+ ("yaffs: MTD device does not support required "
+ "functions\n"));;
+ return NULL;
+ }
+ } else if (yaffs_version == 2) {
/* Check for version 2 style functions */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
if (!mtd->_erase ||
@@ -3137,7 +3155,26 @@
param->empty_lost_n_found = options.empty_lost_and_found;
/* ... and the functions. */
- if (yaffs_version == 2) {
+ if (yaffs_version == 2 && mtd->type == MTD_NORFLASH) {
+ param->write_chunk_tags_fn =
+ normtd2_WriteChunkWithTagsToNAND;
+ param->read_chunk_tags_fn =
+ normtd2_ReadChunkWithTagsFromNAND;
+ param->bad_block_fn = normtd2_MarkNANDBlockBad;
+ param->query_block_fn = normtd2_QueryNANDBlock;
+ param->erase_fn = normtd_EraseBlockInNAND;
+ param->initialise_flash_fn = normtd_InitialiseNAND;
+
+ param->is_yaffs2 = 1;
+ param->total_bytes_per_chunk = 1024;
+ param->chunks_per_block = mtd->erasesize /
(param->total_bytes_per_chunk + 16);
+ nBlocks = (uint32_t) mtd->size / mtd->erasesize;
+ yaffs_dev_to_lc(dev)->spareBuffer = YMALLOC(16);
+
+ param->start_block = 0;
+ param->end_block = nBlocks - 1;
+ } else if (yaffs_version == 2) {
param->write_chunk_tags_fn =
nandmtd2_WriteChunkWithTagsToNAND;
param->read_chunk_tags_fn =
@@ -3173,8 +3210,11 @@
param->is_yaffs2 = 0;
}
/* ... and common functions */
- param->erase_fn = nandmtd_EraseBlockInNAND;
- param->initialise_flash_fn = nandmtd_InitialiseNAND;
+ if(mtd->type != MTD_NORFLASH) {
+ param->erase_fn = nandmtd_EraseBlockInNAND;
+ param->initialise_flash_fn = nandmtd_InitialiseNAND;
+ }
yaffs_dev_to_lc(dev)->putSuperFunc = yaffs_MTDPutSuper;
added file yaffs_mtdif2_nor.c
@@ -0,0 +1,172 @@
+#include "yportenv.h"
+#include "yaffs_trace.h"
+
+
+#include "yaffs_mtdif2_nor.h"
+
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+
+#include "yaffs_packedtags2.h"
+#include "yaffs_linux.h"
+
+#define NOR_OOB_SIZE 16
+#define NOR_PAGE_SIZE(x) (x + NOR_OOB_SIZE)
+
+static inline loff_t chunkToAddr(yaffs_dev_t *dev, struct mtd_info *mtd,
+ int chunkInNAND)
+{
+ return mtd->erasesize * (chunkInNAND / dev->param.chunks_per_block)
+ + NOR_PAGE_SIZE(dev->param.total_bytes_per_chunk)
+ * (chunkInNAND % dev->param.chunks_per_block);
+}
+
+int normtd2_WriteChunkWithTagsToNAND(yaffs_dev_t *dev, int chunkInNAND,
+ const __u8 * data,
+ const yaffs_ext_tags *tags)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ size_t dummy;
+ int retval = 0;
+
+ loff_t addr = chunkToAddr(dev, mtd, chunkInNAND);
+
+ yaffs_PackedTags2 pt;
+
+ T(YAFFS_TRACE_MTD,
+ (TSTR
+ ("normtd2_WriteChunkWithTagsToNAND chunk %d addr 0x%08llx data
%p tags %p"
+ TENDSTR), chunkInNAND, addr, data, tags));
+
+ if (data && tags) {
+ // Calculates ECC, but doesn't write it, return NOR_OOB_SIZE
+ yaffs_PackTags2(&pt, tags, NOR_OOB_SIZE);
+
+ retval = mtd->_write(mtd, addr,
dev->param.total_bytes_per_chunk,
+ &dummy, data);
+ if (retval == 0) {
+ retval = mtd->_write(mtd, addr +
dev->param.total_bytes_per_chunk,
+ NOR_OOB_SIZE, &dummy, (__u8 *) &pt);
+ }
+ } else
+ BUG(); /* both tags and data should always be present */
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+int normtd2_ReadChunkWithTagsFromNAND(yaffs_dev_t *dev, int chunkInNAND,
+ __u8 * data, yaffs_ext_tags *tags)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ size_t dummy;
+ int retval = 0;
+
+ loff_t addr = chunkToAddr(dev, mtd, chunkInNAND);
+
+ yaffs_PackedTags2 pt;
+
+ T(YAFFS_TRACE_MTD,
+ (TSTR
+ ("normtd2_ReadChunkWithTagsFromNAND chunk %d addr 0x%08llx
data %p tags %p"
+ TENDSTR), chunkInNAND, addr, data, tags));
+
+ if (data) {
+ retval = mtd->_read(mtd, addr,
dev->param.total_bytes_per_chunk, &dummy, data);
+ }
+ if (tags && retval == 0) {
+ retval = mtd->_read(mtd, addr + dev->param.total_bytes_per_chunk,
+ NOR_OOB_SIZE, &dummy,
yaffs_dev_to_lc(dev)->spareBuffer);
+ memcpy(&pt, yaffs_dev_to_lc(dev)->spareBuffer, sizeof(pt));
+ }
+
+ if (tags)
+ yaffs_unpack_tags2(tags, &pt, 1); // Ignore ecc
+
+ if (retval == -EUCLEAN) {
+ if (tags) tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
+ retval = 0;
+ }
+
+ if (tags && retval == -EBADMSG && tags->ecc_result ==
YAFFS_ECC_RESULT_NO_ERROR)
+ tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+int normtd2_MarkNANDBlockBad(struct yaffs_dev_s *dev, int blockNo)
+{
+ return YAFFS_OK;
+}
+
+int normtd2_QueryNANDBlock(struct yaffs_dev_s *dev, int blockNo,
+ yaffs_block_state_t *state, int *sequenceNumber)
+{
+ int retval = 0;
+ yaffs_ext_tags t;
+
+ T(YAFFS_TRACE_MTD,
+ (TSTR("normtd2_QueryNANDBlock %d" TENDSTR), blockNo));
+
+ retval = normtd2_ReadChunkWithTagsFromNAND(dev,
+ blockNo *
+ dev->param.total_bytes_per_chunk, NULL,
+ &t);
+
+ if (t.chunk_used) {
+ *sequenceNumber = t.seq_number;
+ *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
+ } else {
+ *sequenceNumber = 0;
+ *state = YAFFS_BLOCK_STATE_EMPTY;
+ }
+
+ T(YAFFS_TRACE_MTD,
+ (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
+ *state));
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+int normtd_EraseBlockInNAND(yaffs_dev_t *dev, int blockNumber)
+{
+ struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
+ __u32 addr = ((loff_t) blockNumber) * mtd->erasesize;
+ struct erase_info ei;
+ int retval = 0;
+
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = mtd->erasesize;
+ ei.time = 1000;
+ ei.retries = 2;
+ ei.callback = NULL;
+ ei.priv = (u_long) dev;
+
+ /* Todo finish off the ei if required */
+
+ T(YAFFS_TRACE_MTD,
+ (TSTR("normtd_EraseBlockInNAND block %d, addr 0x%08x, len %lld"
+ TENDSTR), blockNumber, addr, ei.len));
+
+ retval = mtd->_erase(mtd, &ei);
+
+ if (retval == 0)
+ return YAFFS_OK;
+ else
+ return YAFFS_FAIL;
+}
+
+int normtd_InitialiseNAND(yaffs_dev_t *dev)
+{
+ return YAFFS_OK;
+}
Modified yaffs Makefile
@@ -7,7 +7,7 @@
yaffs-y := yaffs_ecc.o yaffs_vfs_glue.o yaffs_guts.o yaffs_checkptrw.o
yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
-yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
+yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o yaffs_mtdif2_nor.o
yaffs-y += yaffs_nameval.o
yaffs-y += yaffs_allocator.o
yaffs-y += yaffs_yaffs1.o
This will now give you the ability to mount the SPI NOR Flash chip (
w25q128 ) as yaffs2.
Now you will need the architecture code
@@ -0,0 +1,154 @@
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+#include <linux/etherdevice.h>
+#include <linux/ar8216_platform.h>
+#include <linux/rle.h>
+#include <linux/routerboot.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/irq.h>
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+#include "common.h"
+#include "dev-ap9x-pci.h"
+#include "dev-eth.h"
+#include "dev-spi.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-m25p80.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+#include "routerboot.h"
+
+#define RB_ROUTERBOOT_OFFSET 0x0000
+#define RB_ROUTERBOOT_SIZE 0xe000
+#define RB_HARD_CFG_OFFSET 0xe000
+#define RB_HARD_CFG_SIZE 0x1000
+
+#define RB_ART_SIZE 0x10000
+
+static struct gpio_led rb_map_leds_gpio[] __initdata = {
+ {
+ .name = "rb:user",
+ .gpio = 21,
+ .active_low = 1,
+ }, {
+ .name = "rb:led:eth1",
+ .gpio = 18,
+ .active_low = 1,
+ }, {
+ .name = "rb:led:eth2",
+ .gpio = 20,
+ .active_low = 1,
+ }, {
+ .name = "rb:led:poe",
+ .gpio = 19,
+ .active_low = 1,
+ .default_state = LEDS_GPIO_DEFSTATE_ON
+ }, {
+ .name = "rb:led:wlan",
+ .gpio = 22,
+ .active_low = 1,
+ }, {
+ .name = "rb:led5",
+ .gpio = 23,
+ .active_low = 1,
+ }
+};
+
+static struct mtd_partition rbmap_spi_partitions[] = {
+ {
+ .name = "RouterBoot",
+ .offset = 0,
+ .size = 128 * 1024,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ {
+ .name = "kernel",
+ .offset = 0xa00000,
+ .size = MTDPART_SIZ_FULL
+ },
+ {
+ .name = "rootfs",
+ .offset = 128 * 1024,
+ .size = 0x9e0000
+ }
+};
+
+static struct flash_platform_data rbmap_spi_flash_data = {
+ .parts = rbmap_spi_partitions,
+ .nr_parts = ARRAY_SIZE(rbmap_spi_partitions),
+};
+
+static void __init rbmap_wlan_init(void)
+{
+ u8 *hard_cfg = (u8 *) KSEG1ADDR(0x1f000000 + RB_HARD_CFG_OFFSET);
+ u16 tag_len;
+ u8 *tag;
+ char *art_buf;
+ u8 wlan_mac[ETH_ALEN];
+ int err;
+
+ err = routerboot_find_tag(hard_cfg, RB_HARD_CFG_SIZE, RB_ID_WLAN_DATA,
+ &tag, &tag_len);
+ if (err) {
+ pr_err("no calibration data found\n");
+ return;
+ }
+
+ art_buf = kmalloc(RB_ART_SIZE, GFP_KERNEL);
+ if (art_buf == NULL) {
+ pr_err("no memory for calibration data\n");
+ return;
+ }
+
+ err = rle_decode((char *) tag, tag_len, art_buf, RB_ART_SIZE,
+ NULL, NULL);
+ if (err) {
+ pr_err("unable to decode calibration data\n");
+ goto free;
+ }
+
+ ath79_init_mac(wlan_mac, ath79_mac_base, 11);
+ ath79_register_wmac(art_buf + 0x1000, wlan_mac);
+
+free:
+ kfree(art_buf);
+}
+
+static void __init rbmap_setup(void)
+{
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(rb_map_leds_gpio),
+ rb_map_leds_gpio);
+
+ ath79_register_m25p80(&rbmap_spi_flash_data);
+ ath79_register_mdio(0, 0x0);
+
+ ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
+ ath79_register_eth(0);
+
+ ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
+ ath79_register_eth(1);
+
+ ath79_register_usb();
+
+ rbmap_wlan_init();
+
+ gpio_request_one(26,
+ GPIOF_OUT_INIT_HIGH | GPIOF_EXPORT_DIR_CHANGEABLE,
+ "rb:poe");
+}
+
+MIPS_MACHINE(ATH79_MACH_RB_MAP, "mAP", "Mikrotik mAP2n",
+ rbmap_setup);
+
+MIPS_MACHINE(ATH79_MACH_RB_CAP, "cm2n", "Mikrotik cAP2n",
+ rbmap_setup);