SPI/25L64

About

This article covers how to connect serial SPI flash memory to your Carambola. I use M25P64 flash memory in this case which is 8MB.

Connecting

Building firmware

  • Get latest OpenWrt repository and build freshly.
  • Enter make menuconfig and enable
    • Kernel modules
      • SPI Support
        • kmod-spi-dev
  • Edit file

nano build_dir/linux-ramips_rt305x/linux-2.6.39.4/arch/mips/ralink/rt305x/mach-carambola.c

  • Or if you want to edit before build:

nano target/linux/ramips/files/arch/mips/ralink/rt305x/mach-carambola.c

Replace content with file:

/*
 *  CARAMBOLA board support
 *
 *  Copyright (C) 2011 Darius Augulis <darius@8devices.com>
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License version 2 as published
 *  by the Free Software Foundation.
 */

#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>

#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>

#include <asm/mach-ralink/machine.h>
#include <asm/mach-ralink/rt305x.h>
#include <asm/mach-ralink/rt305x_regs.h>
#include <asm/sizes.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>

#include "devices.h"

#ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition carambola_partitions[] = {
	{
    		.name   = "u-boot",
		.offset = 0,
  		.size   = SZ_128K + SZ_64K,
	}, {
		.name   = "u-boot-env",
		.offset = MTDPART_OFS_APPEND,
		.size   = SZ_64K,
	}, {
		.name   = "factory",
		.offset = MTDPART_OFS_APPEND,
 		.size   = SZ_64K,
	}, {
		.name   = "kernel",
		.offset = SZ_256K + SZ_64K,
		.size   = SZ_1M,
	}, {
		.name   = "rootfs",
		.offset = SZ_256K + SZ_64K + SZ_1M,
		.size   = SZ_4M + SZ_2M,
	}, {
		.name   = "openwrt",
		.offset = SZ_256K + SZ_64K,
  		.size   = SZ_4M + SZ_2M + SZ_1M,
	}
};
#endif /* CONFIG_MTD_PARTITIONS */

static struct physmap_flash_data carambola_flash_data = {
#ifdef CONFIG_MTD_PARTITIONS
	.nr_parts	= ARRAY_SIZE(carambola_partitions),
	.parts		= carambola_partitions,
#endif
};


static int __init carambola_register_gpiodev(void)
{
       static struct resource res = {
               .start = 0xFFFFFFFF,
       };
         struct platform_device *pdev;

       pdev = platform_device_register_simple("GPIODEV", 0, &res, 1);
       if (!pdev) {
               printk(KERN_ERR "carambole: GPIODEV init failed\n");
               return -ENODEV;
       }
  
       return 0;
    }
  
static struct i2c_gpio_platform_data carambola_i2c_gpio_data = {
	.sda_pin        = 1,
  	.scl_pin        = 2,
};  

static struct platform_device carambola_i2c_gpio = {
	.name           = "i2c-gpio",
	.id             = 0,
	.dev     = {
		.platform_data  = &carambola_i2c_gpio_data,
	},
};  

#ifdef CONFIG_MTD_PARTITIONS
static struct mtd_partition spiflash_partitions[] = {
	{
	.name	= "data",
		.offset	= 0,
		.size	= 0x800000,	/* 8MB flash */
//		.mask_flags = MTD_WRITEABLE,
	}
};
#endif /* CONFIG_MTD_PARTITIONS */

static const struct flash_platform_data spiflash_flash = {
	.type		= "w25x64",
#ifdef CONFIG_MTD_PARTITIONS
	.parts		= spiflash_partitions,
	.nr_parts	= ARRAY_SIZE(spiflash_partitions),
#endif
};

static struct spi_board_info __initdata spiflash_spi_slave_info[] = {
        {
                .modalias       = "m25p80",
                .platform_data  = &spiflash_flash,
                .irq            = -1,
                .max_speed_hz   = 52428800,
                .bus_num        = 0,
                .chip_select    = 0,
        },
};

static struct platform_device *carambola_devices[] __initdata = {
        &carambola_i2c_gpio
};

static void __init carambola_init(void)
{
	rt305x_gpio_init((RT305X_GPIO_MODE_GPIO << RT305X_GPIO_MODE_UART0_SHIFT) |
			 RT305X_GPIO_MODE_I2C);
	carambola_register_gpiodev();
	platform_add_devices(carambola_devices, ARRAY_SIZE(carambola_devices));
	rt305x_register_flash(0, &carambola_flash_data);
	rt305x_register_spi(spiflash_spi_slave_info, ARRAY_SIZE(spiflash_spi_slave_info));

	rt305x_esw_data.vlan_config = RT305X_ESW_VLAN_CONFIG_LLLLW;
	rt305x_register_ethernet();
	rt305x_register_wifi();
	rt305x_register_wdt();
	rt305x_register_usb();
}

MIPS_MACHINE(RAMIPS_MACH_CARAMBOLA, "CARAMBOLA", "CARAMBOLA",
	     carambola_init);

Uploading and testing

  • Upload firmware to Carambola

scp test@192.168.0.104:/home/test/carambola_spi_flash/bin/ramips/openwrt-ramips-rt305x-carambola-squashfs-sysupgrade.bin /tmp

Host '192.168.0.104' is not in the trusted hosts file.
(fingerprint md5 02:d9:64:44:60:18:5a:c4:e3:15:6f:02:13:e3:20:eb)
Do you want to continue connecting? (y/n) y
test@192.168.0.104's password: 
openwrt-ramips-rt305x-carambola-squashfs-sysu 100% 2688KB   1.3MB/s   00:02    
  • Flash firmware

sysupgrade -v /tmp/openwrt-ramips-rt305x-carambola-squashfs-sysupgrade.bin

Saving config files...
etc/sysctl.conf
etc/shells
etc/rc.local
etc/profile
etc/passwd
etc/inittab
etc/hosts
etc/group
etc/firewall.user
etc/dropbear/dropbear_rsa_host_key
etc/dropbear/dropbear_dss_host_key
etc/config/wireless
etc/config/system
etc/config/network
etc/config/firewall
etc/config/dropbear
etc/config/dhcp
Sending TERM to remaining processes ... syslogd klogd dnsmasq hotplug2 
Sending KILL to remaining processes ... 
Switching to ramdisk...
Performing system upgrade...
Unlocking firmware ...

Writing from <stdin> to firmware ...     
Appending jffs2 data from /tmp/sysupgrade.tgz to firmware...
Writing from <stdin> to firmware ...     
Upgrade completed
Rebooting system...
Restarting system.
  • Check if Carambola found connected memory

dmesg | grep 25p

m25p80 spi0.0: w25x64 (8192 Kbytes)
  • Check for existence of data block:

cat /proc/mtd

dev:    size   erasesize  name
mtd0: 00030000 00010000 "u-boot"
mtd1: 00010000 00010000 "u-boot-env"
mtd2: 00010000 00010000 "factory"
mtd3: 000d0000 00010000 "kernel"
mtd4: 006e0000 00010000 "rootfs"
mtd5: 00530000 00010000 "rootfs_data"
mtd6: 007b0000 00010000 "firmware"
mtd7: 00800000 00001000 "data"
  • If you have fresh chip, probably you want to erase it

mtd erase mtd7

  • After this you can mount it and use as regular memory device

mount -t jffs2 /dev/mtdblock7 /mnt