[PATCH] mtd: m25p80: add support for Spansion s25fl128s chip

Angus Clark angus.clark at st.com
Thu Dec 5 05:55:34 EST 2013


Hi Huang,

On 12/05/2013 02:51 AM, Brian Norris wrote:
> On Wed, Dec 4, 2013 at 6:20 PM, Huang Shijie <b32955 at freescale.com> wrote:
>> Is there any NOR that can only read out 5bytes, and can not be read out 6 bytes?
> 
> I doubt it. But I wasn't talking about "can we read 6 bytes?", but
> rather "what happens when we compare 6 bytes of ID with the 5 byte IDs
> in the table?". We'll have a mixture of 3-byte, 5-byte and 6-byte IDs
> in our table, and we need to be careful to match properly.
> 

Just in case it is of interest, I have implemented something similar in my own
out-of-tree driver (relevant code segments below).  My 'flash_info' table
structure is a little different to m25p80, but the approach could be similar,
and it has been tested on numerous devices.

/*
 * SPI Flash Device Table
 */
struct flash_info {
	char		*name;

	/* READID data, as returned by 'FLASH_CMD_RDID' (0x9f). */
	u8		readid[MAX_READID_LEN];
	int		readid_len;

	/* The size listed here is what works with FLASH_CMD_SE, which isn't
	 * necessarily called a "sector" by the vendor.
	 */
	unsigned	sector_size;
	u16		n_sectors;

	/* FLASH device capabilities.  Note, in contrast to the other
	 * capabilities, 'FLASH_CAPS_32BITADDR' is set at probe time, based on
	 * the size of the device found.
	 */
	u32		capabilities;

	/* Maximum operating frequency.  Note, where FAST_READ is supported,
	 * freq_max specifies the FAST_READ frequency, not the READ frequency.
	 */
	u32		max_freq;

	int		(*config)(struct stm_spi_fsm *, struct flash_info *);
};

/* Device with standard 3-byte JEDEC ID */
#define JEDEC_INFO(_name, _jedec_id, _sector_size, _n_sectors,		\
		   _capabilities, _max_freq, _config)			\
	{								\
		.name = (_name),					\
		.readid[0] = ((_jedec_id) >> 16 & 0xff),		\
		.readid[1] = ((_jedec_id) >>  8 & 0xff),		\
		.readid[2] = ((_jedec_id) >>  0 & 0xff),		\
		.readid_len = 3,					\
		.sector_size = (_sector_size),				\
		.n_sectors = (_n_sectors),				\
		.capabilities = (_capabilities),			\
		.max_freq = (_max_freq),				\
		.config = (_config)					\
	}

/* Device with arbitrary-length READID */
#define RDID(...) __VA_ARGS__	/* Dummy macro to protect array argument. */
#define RDID_INFO(_name, _readid, _readid_len, _sector_size,		\
		  _n_sectors, _capabilities, _max_freq, _config)	\
	{								\
		.name = (_name),					\
		.readid = _readid,					\
		.readid_len = _readid_len,				\
		.capabilities = (_capabilities),			\
		.sector_size = (_sector_size),				\
		.n_sectors = (_n_sectors),				\
		.capabilities = (_capabilities),			\
		.max_freq = (_max_freq),				\
		.config = (_config)					\
	}


static struct flash_info __devinitdata flash_types[] = {

#define M25P_CAPS (FLASH_CAPS_READ_WRITE | FLASH_CAPS_READ_FAST)
	JEDEC_INFO("m25p40",  0x202013,  64 * 1024,   8, M25P_CAPS, 25, NULL),
	JEDEC_INFO("m25p80",  0x202014,  64 * 1024,  16, M25P_CAPS, 25, NULL),
	JEDEC_INFO("m25p16",  0x202015,  64 * 1024,  32, M25P_CAPS, 25, NULL),
	JEDEC_INFO("m25p32",  0x202016,  64 * 1024,  64, M25P_CAPS, 50, NULL),
	JEDEC_INFO("m25p64",  0x202017,  64 * 1024, 128, M25P_CAPS, 50, NULL),
	JEDEC_INFO("m25p128", 0x202018, 256 * 1024,  64, M25P_CAPS, 50, NULL),

#define M25PX_CAPS (FLASH_CAPS_READ_WRITE	| \
		    FLASH_CAPS_READ_FAST	| \
		    FLASH_CAPS_READ_1_1_2	| \
		    FLASH_CAPS_WRITE_1_1_2)
	JEDEC_INFO("m25px32", 0x207116,  64 * 1024,  64, M25PX_CAPS, 75, NULL),
	JEDEC_INFO("m25px64", 0x207117,  64 * 1024, 128, M25PX_CAPS, 75, NULL),

	/* Spansion S25FLxxxP
	 *     - 256KiB and 64KiB sector variants (identified by ext. JEDEC)
	 *     - S25FL128Px devices do not support DUAL or QUAD I/O
	 */
#define S25FLXXXP_CAPS (FLASH_CAPS_READ_WRITE	| \
			FLASH_CAPS_READ_1_1_2	| \
			FLASH_CAPS_READ_1_2_2	| \
			FLASH_CAPS_READ_1_1_4	| \
			FLASH_CAPS_READ_1_4_4	| \
			FLASH_CAPS_WRITE_1_1_4	| \
			FLASH_CAPS_READ_FAST)
	RDID_INFO("s25fl032p", RDID({0x01, 0x02, 0x15, 0x4d, 0x00}), 5,
		  64 * 1024,  64, S25FLXXXP_CAPS, 80, s25fl_config),
	RDID_INFO("s25fl128p1", RDID({0x01, 0x20, 0x18, 0x03, 0x00}), 5,
		  256 * 1024, 64,
		 (FLASH_CAPS_READ_WRITE | FLASH_CAPS_READ_FAST), 104, NULL),
	RDID_INFO("s25fl128p0", RDID({0x01, 0x20, 0x18, 0x03, 0x01}), 5,
		  64 * 1024, 256,
		  (FLASH_CAPS_READ_WRITE | FLASH_CAPS_READ_FAST), 104, NULL),
	RDID_INFO("s25fl129p0", RDID({0x01, 0x20, 0x18, 0x4d, 0x00}), 5,
		  256 * 1024,  64, S25FLXXXP_CAPS, 80, sstatic int
cmp_flash_info_readid_len(const void *a, const void *b)
{
	return ((struct flash_info *)b)->readid_len -
		((struct flash_info *)a)->readid_len;
}
25fl_config),
	RDID_INFO("s25fl129p1", RDID({0x01, 0x20, 0x18, 0x4d, 0x01}), 5,
		  64 * 1024, 256, S25FLXXXP_CAPS, 80, s25fl_config),

	/* Spansion S25FLxxxS
	 *     - 256KiB and 64KiB sector variants (identified by ext. JEDEC)
	 *     - RESET# signal supported by die but not bristled out on all
	 *       package types.  The package type is a function of board design,
	 *       so this information is captured in the board's capabilities.
	 *     - Supports 'DYB' sector protection. Depending on variant, sectors
	 *       may default to locked state on power-on.
	 *     - S25FL127Sx handled as S25FL128Sx
	 */
#define S25FLXXXS_CAPS (S25FLXXXP_CAPS		| \
			FLASH_CAPS_RESET	| \
			FLASH_CAPS_DYB_LOCKING)
	RDID_INFO("s25fl128s0", RDID({0x01, 0x20, 0x18, 0x4d, 0x00, 0x80}), 6,
		  256 * 1024, 64, S25FLXXXS_CAPS, 80, s25fl_config),
	RDID_INFO("s25fl128s1", RDID({0x01, 0x20, 0x18, 0x4d, 0x01, 0x80}), 6,
		  64 * 1024, 256, S25FLXXXS_CAPS, 80, s25fl_config),
	RDID_INFO("s25fl256s0", RDID({0x01, 0x02, 0x19, 0x4d, 0x00, 0x80}), 6,
		  256 * 1024, 128, S25FLXXXS_CAPS, 80, s25fl_config),
	RDID_INFO("s25fl256s1", RDID({0x01, 0x02, 0x19, 0x4d, 0x01, 0x80}), 6,
		  64 * 1024, 512, S25FLXXXS_CAPS, 80, s25fl_config),

	{ },
};

static int cmp_flash_info_readid_len(const void *a, const void *b)
{
	return ((struct flash_info *)b)->readid_len -
		((struct flash_info *)a)->readid_len;
}

static struct flash_info *__devinit fsm_jedec_probe(struct stm_spi_fsm *fsm)
{
	uint8_t	readid[MAX_READID_LEN];
	char readid_str[MAX_READID_LEN * 3 + 1];
	struct flash_info *info;

	if (fsm_read_jedec(fsm, readid) != 0) {
		dev_info(fsm->dev, "error reading JEDEC ID\n");
		return NULL;
	}

	hex_dump_to_buffer(readid, MAX_READID_LEN, 16, 1,
			   readid_str, sizeof(readid_str), 0);

	dev_dbg(fsm->dev, "READID = %s\n", readid_str);

	/* The 'readid' may match multiple entries in the table.  To ensure we
	 * retrieve the most specific match, the table is sorted in order of
	 * 'readid_len'.
	 */
	sort(flash_types, ARRAY_SIZE(flash_types) - 1,
	     sizeof(struct flash_info), cmp_flash_info_readid_len, NULL);

	for (info = flash_types; info->name; info++) {
		if (memcmp(info->readid, readid, info->readid_len) == 0)
			return info;
	}

	dev_err(fsm->dev, "Unrecognized READID [%s]\n", readid_str);

	return NULL;
}

Cheers,

Angus



More information about the linux-mtd mailing list