All of lore.kernel.org
 help / color / mirror / Atom feed
From: John Rigby <jrigby@freescale.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH] mtd: SPI Flash: Support the STMicro Flash
Date: Thu, 28 Aug 2008 12:38:11 -0600	[thread overview]
Message-ID: <48B6F093.8020106@freescale.com> (raw)
In-Reply-To: <1219925773-10907-1-git-send-email-Tsi-Chung.Liew@freescale.com>

Any problem with this going in via the coldfire tree?  Or does someone 
else want to pick it up?

Tsi-Chung Liew wrote:
> From: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
>
> Add MTD SPI Flash support for M25P16, M25P20, M25P32,
> M25P40, M25P64, M25P80, M25P128.
>
> Signed-off-by: Jason McMullan <mcmullan@netapp.com>
> Signed-off-by: TsiChung Liew <Tsi-Chung.Liew@freescale.com>
> ---
>  drivers/mtd/spi/Makefile             |    1 +
>  drivers/mtd/spi/spi_flash.c          |    5 +
>  drivers/mtd/spi/spi_flash_internal.h |    1 +
>  drivers/mtd/spi/stmicro.c            |  356 ++++++++++++++++++++++++++++++++++
>  4 files changed, 363 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mtd/spi/stmicro.c
>
> diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
> index af6af97..3d4f892 100644
> --- a/drivers/mtd/spi/Makefile
> +++ b/drivers/mtd/spi/Makefile
> @@ -27,6 +27,7 @@ LIB	:= $(obj)libspi_flash.a
>  
>  COBJS-$(CONFIG_SPI_FLASH)	+= spi_flash.o
>  COBJS-$(CONFIG_SPI_FLASH_ATMEL)	+= atmel.o
> +COBJS-$(CONFIG_SPI_FLASH_STMICRO)	+= stmicro.o
>  
>  COBJS	:= $(COBJS-y)
>  SRCS	:= $(COBJS:.o=.c)
> diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
> index d581cb3..d1d81af 100644
> --- a/drivers/mtd/spi/spi_flash.c
> +++ b/drivers/mtd/spi/spi_flash.c
> @@ -134,6 +134,11 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
>  		flash = spi_flash_probe_atmel(spi, idcode);
>  		break;
>  #endif
> +#ifdef CONFIG_SPI_FLASH_STMICRO
> +	case 0x20:
> +		flash = spi_flash_probe_stmicro(spi, idcode);
> +		break;
> +#endif
>  	default:
>  		debug("SF: Unsupported manufacturer %02X\n", idcode[0]);
>  		flash = NULL;
> diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h
> index 1438050..e5f758e 100644
> --- a/drivers/mtd/spi/spi_flash_internal.h
> +++ b/drivers/mtd/spi/spi_flash_internal.h
> @@ -43,3 +43,4 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
>  /* Manufacturer-specific probe functions */
>  struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode);
>  struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode);
> +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 *idcode);
> diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c
> new file mode 100644
> index 0000000..c999b12
> --- /dev/null
> +++ b/drivers/mtd/spi/stmicro.c
> @@ -0,0 +1,356 @@
> +/*
> + * (C) Copyright 2000-2002
> + * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
> + *
> + * Copyright 2008, Network Appliance Inc.
> + * Jason McMullan <mcmullan@netapp.com>
> + *
> + * Copyright (C) 2004-2007 Freescale Semiconductor, Inc.
> + * TsiChung Liew (Tsi-Chung.Liew at freescale.com)
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <malloc.h>
> +#include <spi_flash.h>
> +
> +#include "spi_flash_internal.h"
> +
> +/* M25Pxx-specific commands */
> +#define CMD_M25PXX_WREN		0x06	/* Write Enable */
> +#define CMD_M25PXX_WRDI		0x04	/* Write Disable */
> +#define CMD_M25PXX_RDSR		0x05	/* Read Status Register */
> +#define CMD_M25PXX_WRSR		0x01	/* Write Status Register */
> +#define CMD_M25PXX_READ		0x03	/* Read Data Bytes */
> +#define CMD_M25PXX_FAST_READ	0x0b	/* Read Data Bytes at Higher Speed */
> +#define CMD_M25PXX_PP		0x02	/* Page Program */
> +#define CMD_M25PXX_SE		0xd8	/* Sector Erase */
> +#define CMD_M25PXX_BE		0xc7	/* Bulk Erase */
> +#define CMD_M25PXX_DP		0xb9	/* Deep Power-down */
> +#define CMD_M25PXX_RES		0xab	/* Release from DP, and Read Signature */
> +
> +#define STM_ID_M25P16		0x15
> +#define STM_ID_M25P20		0x12
> +#define STM_ID_M25P32		0x16
> +#define STM_ID_M25P40		0x13
> +#define STM_ID_M25P64		0x17
> +#define STM_ID_M25P80		0x14
> +#define STM_ID_M25P128		0x18
> +
> +#define STMICRO_SR_WIP		(1 << 0)	/* Write-in-Progress */
> +
> +struct stmicro_spi_flash_params {
> +	u8 idcode1;
> +	u16 page_size;
> +	u16 pages_per_sector;
> +	u16 nr_sectors;
> +	const char *name;
> +};
> +
> +struct stmicro_spi_flash {
> +	const struct stmicro_spi_flash_params *params;
> +	struct spi_flash flash;
> +};
> +
> +static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash
> +							     *flash)
> +{
> +	return container_of(flash, struct stmicro_spi_flash, flash);
> +}
> +
> +static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = {
> +	{
> +		.idcode1 = STM_ID_M25P16,
> +		.page_size = 256,
> +		.pages_per_sector = 256,
> +		.nr_sectors = 32,
> +		.name = "M25P16",
> +	},
> +	{
> +		.idcode1 = STM_ID_M25P20,
> +		.page_size = 256,
> +		.pages_per_sector = 256,
> +		.nr_sectors = 4,
> +		.name = "M25P20",
> +	},
> +	{
> +		.idcode1 = STM_ID_M25P32,
> +		.page_size = 256,
> +		.pages_per_sector = 256,
> +		.nr_sectors = 64,
> +		.name = "M25P32",
> +	},
> +	{
> +		.idcode1 = STM_ID_M25P40,
> +		.page_size = 256,
> +		.pages_per_sector = 256,
> +		.nr_sectors = 8,
> +		.name = "M25P40",
> +	},
> +	{
> +		.idcode1 = STM_ID_M25P64,
> +		.page_size = 256,
> +		.pages_per_sector = 256,
> +		.nr_sectors = 128,
> +		.name = "M25P64",
> +	},
> +	{
> +		.idcode1 = STM_ID_M25P80,
> +		.page_size = 256,
> +		.pages_per_sector = 256,
> +		.nr_sectors = 16,
> +		.name = "M25P80",
> +	},
> +	{
> +		.idcode1 = STM_ID_M25P128,
> +		.page_size = 256,
> +		.pages_per_sector = 1024,
> +		.nr_sectors = 64,
> +		.name = "M25P128",
> +	},
> +};
> +
> +static int stmicro_wait_ready(struct spi_flash *flash, unsigned long timeout)
> +{
> +	struct spi_slave *spi = flash->spi;
> +	unsigned long timebase;
> +	int ret;
> +	u8 status;
> +	u8 cmd[4] = { CMD_M25PXX_RDSR, 0xff, 0xff, 0xff };
> +
> +	ret = spi_xfer(spi, 32, &cmd[0], NULL, SPI_XFER_BEGIN);
> +	if (ret) {
> +		debug("SF: Failed to send command %02x: %d\n", cmd, ret);
> +		return ret;
> +	}
> +
> +	timebase = get_timer(0);
> +	do {
> +		ret = spi_xfer(spi, 8, NULL, &status, 0);
> +		if (ret)
> +			return -1;
> +
> +		if ((status & STMICRO_SR_WIP) == 0)
> +			break;
> +
> +	} while (get_timer(timebase) < timeout);
> +
> +	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
> +
> +	if ((status & STMICRO_SR_WIP) == 0)
> +		return 0;
> +
> +	/* Timed out */
> +	return -1;
> +}
> +
> +static int stmicro_read_fast(struct spi_flash *flash,
> +			     u32 offset, size_t len, void *buf)
> +{
> +	struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
> +	unsigned long page_addr;
> +	unsigned long page_size;
> +	u8 cmd[5];
> +
> +	page_size = stm->params->page_size;
> +	page_addr = offset / page_size;
> +
> +	cmd[0] = CMD_READ_ARRAY_FAST;
> +	cmd[1] = page_addr >> 8;
> +	cmd[2] = page_addr;
> +	cmd[3] = offset % page_size;
> +	cmd[4] = 0x00;
> +
> +	return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
> +}
> +
> +static int stmicro_write(struct spi_flash *flash,
> +			 u32 offset, size_t len, const void *buf)
> +{
> +	struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
> +	unsigned long page_addr;
> +	unsigned long byte_addr;
> +	unsigned long page_size;
> +	size_t chunk_len;
> +	size_t actual;
> +	int ret;
> +	u8 cmd[4];
> +
> +	page_size = stm->params->page_size;
> +	page_addr = offset / page_size;
> +	byte_addr = offset % page_size;
> +
> +	ret = spi_claim_bus(flash->spi);
> +	if (ret) {
> +		debug("SF: Unable to claim SPI bus\n");
> +		return ret;
> +	}
> +
> +	ret = 0;
> +	for (actual = 0; actual < len; actual += chunk_len) {
> +		chunk_len = min(len - actual, page_size - byte_addr);
> +
> +		cmd[0] = CMD_M25PXX_PP;
> +		cmd[1] = page_addr >> 8;
> +		cmd[2] = page_addr;
> +		cmd[3] = byte_addr;
> +
> +		debug
> +		    ("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %d\n",
> +		     buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
> +
> +		ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
> +		if (ret < 0) {
> +			debug("SF: Enabling Write failed\n");
> +			break;
> +		}
> +
> +		ret = spi_flash_cmd_write(flash->spi, cmd, 4,
> +					  buf + actual, chunk_len);
> +		if (ret < 0) {
> +			debug("SF: STMicro Page Program failed\n");
> +			break;
> +		}
> +
> +		ret = stmicro_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
> +		if (ret < 0) {
> +			debug("SF: STMicro page programming timed out\n");
> +			break;
> +		}
> +
> +		page_addr++;
> +		byte_addr = 0;
> +	}
> +
> +	debug("SF: STMicro: Successfully programmed %u bytes @ 0x%x\n",
> +	      len, offset);
> +
> +	spi_release_bus(flash->spi);
> +	return ret;
> +}
> +
> +int stmicro_erase(struct spi_flash *flash, u32 offset, size_t len)
> +{
> +	struct stmicro_spi_flash *stm = to_stmicro_spi_flash(flash);
> +	unsigned long sector_size;
> +	size_t actual;
> +	int ret;
> +	u8 cmd[4];
> +
> +	/*
> +	 * This function currently uses sector erase only.
> +	 * probably speed things up by using bulk erase
> +	 * when possible.
> +	 */
> +
> +	sector_size = stm->params->page_size * stm->params->pages_per_sector;
> +
> +	if (offset % sector_size || len % sector_size) {
> +		debug("SF: Erase offset/length not multiple of sector size\n");
> +		return -1;
> +	}
> +
> +	len /= sector_size;
> +	cmd[0] = CMD_M25PXX_SE;
> +	cmd[2] = 0x00;
> +	cmd[3] = 0x00;
> +
> +	ret = spi_claim_bus(flash->spi);
> +	if (ret) {
> +		debug("SF: Unable to claim SPI bus\n");
> +		return ret;
> +	}
> +
> +	ret = 0;
> +	for (actual = 0; actual < len; actual++) {
> +		cmd[1] = (offset / sector_size) + actual;
> +
> +		ret = spi_flash_cmd(flash->spi, CMD_M25PXX_WREN, NULL, 0);
> +		if (ret < 0) {
> +			debug("SF: Enabling Write failed\n");
> +			break;
> +		}
> +
> +		ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
> +		if (ret < 0) {
> +			debug("SF: STMicro page erase failed\n");
> +			break;
> +		}
> +
> +		/* Up to 2 seconds */
> +		ret = stmicro_wait_ready(flash, 2 * CFG_HZ);
> +		if (ret < 0) {
> +			debug("SF: STMicro page erase timed out\n");
> +			break;
> +		}
> +	}
> +
> +	debug("SF: STMicro: Successfully erased %u bytes @ 0x%x\n",
> +	      len * sector_size, offset);
> +
> +	spi_release_bus(flash->spi);
> +	return ret;
> +}
> +
> +struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode)
> +{
> +	const struct stmicro_spi_flash_params *params;
> +	struct stmicro_spi_flash *stm;
> +	unsigned int i;
> +	int ret;
> +	u8 id[3];
> +
> +	ret = spi_flash_cmd(spi, CMD_READ_ID, id, sizeof(id));
> +	if (ret)
> +		return NULL;
> +
> +	for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) {
> +		params = &stmicro_spi_flash_table[i];
> +		if (params->idcode1 == idcode[2]) {
> +			break;
> +		}
> +	}
> +
> +	if (i == ARRAY_SIZE(stmicro_spi_flash_table)) {
> +		debug("SF: Unsupported STMicro ID %02x\n", id[1]);
> +		return NULL;
> +	}
> +
> +	stm = malloc(sizeof(struct stmicro_spi_flash));
> +	if (!stm) {
> +		debug("SF: Failed to allocate memory\n");
> +		return NULL;
> +	}
> +
> +	stm->params = params;
> +	stm->flash.spi = spi;
> +	stm->flash.name = params->name;
> +
> +	stm->flash.write = stmicro_write;
> +	stm->flash.erase = stmicro_erase;
> +	stm->flash.read = stmicro_read_fast;
> +	stm->flash.size = params->page_size * params->pages_per_sector
> +	    * params->nr_sectors;
> +
> +	debug("SF: Detected %s with page size %u, total %u bytes\n",
> +	      params->name, params->page_size, stm->flash.size);
> +
> +	return &stm->flash;
> +}
>   

  reply	other threads:[~2008-08-28 18:38 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-28 12:16 [U-Boot] [PATCH] mtd: SPI Flash: Support the STMicro Flash Tsi-Chung Liew
2008-08-28 18:38 ` John Rigby [this message]
2008-09-01 16:28   ` Haavard Skinnemoen
  -- strict thread matches above, loose matches on Subject: below --
2008-08-22 16:12 Tsi-Chung Liew
2008-08-28 12:49 ` Haavard Skinnemoen
2008-08-28 13:44   ` Liew Tsi Chung-R5AAHP
2008-08-28 17:00     ` Scott Wood
2008-08-28 17:06       ` Liew Tsi Chung-R5AAHP
2008-08-28 17:07         ` Scott Wood
2008-08-22 16:00 Tsi-Chung Liew
2008-08-21 17:48 Tsi-Chung Liew
2008-08-22  7:09 ` Haavard Skinnemoen
2008-08-22 17:02   ` Liew Tsi Chung-R5AAHP

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=48B6F093.8020106@freescale.com \
    --to=jrigby@freescale.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.