mtd: SPI Flash: Support the STMicro Flash
Subsystems (2)
PATCH 1/1 mtd: SPI Flash: Support the STMicro Flash
From: TsiChung Liew <[email protected]>
Add MTD SPI Flash support for M25P16, M25P20, M25P32, M25P40, M25P64, M25P80, M25P128.
Signed-off-by Jason McMullan <[email protected]>
Signed-off-by TsiChung Liew <[email protected]>
--- 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
drivers/mtd/spi/Makefile +1 -0
@@ -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)
drivers/mtd/spi/spi_flash.c +5 -0
@@ -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 ;
drivers/mtd/spi/spi_flash_internal.h +1 -0
@@ -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);
drivers/mtd/spi/stmicro.c new file +356 -0
356 lines not on this page · raw message
Signature · 1 line
1.5.6.4
PATCH 1/1 mtd: SPI Flash: Support the STMicro Flash
Any problem with this going in via the coldfire tree? Or does someone else want to pick it up?
Quoted 415 lines · Tsi-Chung Liew
From: TsiChung Liew <[email protected]>
Add MTD SPI Flash support for M25P16, M25P20, M25P32, M25P40, M25P64, M25P80, M25P128.
Signed-off-by Jason McMullan <[email protected]>Signed-off-by TsiChung Liew <[email protected]>--- 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.cdrivers/mtd/spi/Makefile +1
-0@@ -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)drivers/mtd/spi/spi_flash.c +5
-0@@ -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 ;drivers/mtd/spi/spi_flash_internal.h +1
-0@@ -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);drivers/mtd/spi/stmicro.c new file +356
-0@@ -0,0 +1,356 @@ +/* +* (C) Copyright 2000-2002 +* Wolfgang Denk, DENX Software Engineering, wd at denx.de. +* +* Copyright 2008, Network Appliance Inc. +* Jason McMullan <[email protected]> +* +* 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; +}
PATCH 1/1 mtd: SPI Flash: Support the STMicro Flash
Quoted 2 lines · John Rigby
Any problem with this going in via the coldfire tree? Or does someone else want to pick it up?
Fine with me.
Haavard