diff options
| author | Piotr Ziecik <kosmo@semihalf.com> | 2008-11-17 15:57:58 +0100 | 
|---|---|---|
| committer | Stefan Roese <sr@denx.de> | 2008-11-24 11:05:25 +0100 | 
| commit | 91809ed51d8327a8dbbf29aa98a091154c282171 (patch) | |
| tree | e57f9ab8c520575ffabf40626bb7249c0e4c4708 | |
| parent | 6ea808efdf9aa5d9067fbfac32acde8539129ed2 (diff) | |
| download | olio-uboot-2014.01-91809ed51d8327a8dbbf29aa98a091154c282171.tar.xz olio-uboot-2014.01-91809ed51d8327a8dbbf29aa98a091154c282171.zip | |
cfi-mtd: Add cfi-mtd driver.
Add cfi-mtd driver, which exports CFI flash to MTD layer.
This allows CFI flash devices to be used from MTD layer.
Building of the new driver is controlled by CONFIG_FLASH_CFI_MTD
option. Initialization is done by calling cfi_mtd_init() from
flash_init().
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Stefan Roese <sr@denx.de>
| -rw-r--r-- | README | 5 | ||||
| -rw-r--r-- | drivers/mtd/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mtd/cfi_flash.c | 5 | ||||
| -rw-r--r-- | drivers/mtd/cfi_mtd.c | 202 | ||||
| -rw-r--r-- | include/flash.h | 8 | 
5 files changed, 221 insertions, 0 deletions
| @@ -2157,6 +2157,11 @@ Configuration Settings:  		This option also enables the building of the cfi_flash driver  		in the drivers directory +- CONFIG_FLASH_CFI_MTD +		This option enables the building of the cfi_mtd driver +		in the drivers directory. The driver exports CFI flash +		to the MTD layer. +  - CONFIG_SYS_FLASH_USE_BUFFER_WRITE  		Use buffered writes to flash. diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 6538f7a15..47687d0e0 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -27,6 +27,7 @@ LIB	:= $(obj)libmtd.a  COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o  COBJS-$(CONFIG_FLASH_CFI_DRIVER) += cfi_flash.o +COBJS-$(CONFIG_FLASH_CFI_MTD) += cfi_mtd.o  COBJS-$(CONFIG_HAS_DATAFLASH) += dataflash.o  COBJS-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o  COBJS-$(CONFIG_MW_EEPROM) += mw_eeprom.o diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index b8422e15f..e8afe9985 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -2087,5 +2087,10 @@ unsigned long flash_init (void)  			       flash_get_info(apl[i].start));  	}  #endif + +#ifdef CONFIG_FLASH_CFI_MTD +	cfi_mtd_init(); +#endif +  	return (size);  } diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c new file mode 100644 index 000000000..cf82d9278 --- /dev/null +++ b/drivers/mtd/cfi_mtd.c @@ -0,0 +1,202 @@ +/* + * (C) Copyright 2008 Semihalf + * + * Written by: Piotr Ziecik <kosmo@semihalf.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 <flash.h> + +#include <asm/errno.h> +#include <linux/mtd/mtd.h> + +extern flash_info_t flash_info[]; + +static struct mtd_info cfi_mtd_info[CONFIG_SYS_MAX_FLASH_BANKS]; + +static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +{ +	flash_info_t *fi = mtd->priv; +	size_t a_start = fi->start[0] + instr->addr; +	size_t a_end = a_start + instr->len; +	int s_first = -1; +	int s_last = -1; +	int error, sect; + +	for (sect = 0; sect < fi->sector_count - 1; sect++) { +		if (a_start == fi->start[sect]) +			s_first = sect; + +		if (a_end == fi->start[sect + 1]) { +			s_last = sect; +			break; +		} +	} + +	if (s_first >= 0 && s_first <= s_last) { +		instr->state = MTD_ERASING; + +		flash_set_verbose(0); +		error = flash_erase(fi, s_first, s_last); +		flash_set_verbose(1); + +		if (error) { +			instr->state = MTD_ERASE_FAILED; +			return -EIO; +		} + +		instr->state = MTD_ERASE_DONE; +		mtd_erase_callback(instr); +		return 0; +	} + +	return -EINVAL; +} + +static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, +	size_t *retlen, u_char *buf) +{ +	flash_info_t *fi = mtd->priv; +	u_char *f = (u_char*)(fi->start[0]) + from; + +	memcpy(buf, f, len); +	*retlen = len; + +	return 0; +} + +static int cfi_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, +	size_t *retlen, const u_char *buf) +{ +	flash_info_t *fi = mtd->priv; +	u_long t = fi->start[0] + to; +	int error; + +	flash_set_verbose(0); +	error = write_buff(fi, (u_char*)buf, t, len); +	flash_set_verbose(1); + +	if (!error) { +		*retlen = len; +		return 0; +	} + +	return -EIO; +} + +static void cfi_mtd_sync(struct mtd_info *mtd) +{ +	/* +	 * This function should wait until all pending operations +	 * finish. However this driver is fully synchronous, so +	 * this function returns immediately +	 */ +} + +static int cfi_mtd_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ +	flash_info_t *fi = mtd->priv; + +	flash_set_verbose(0); +	flash_protect(FLAG_PROTECT_SET, fi->start[0] + ofs, +					fi->start[0] + ofs + len - 1, fi); +	flash_set_verbose(1); + +	return 0; +} + +static int cfi_mtd_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ +	flash_info_t *fi = mtd->priv; + +	flash_set_verbose(0); +	flash_protect(FLAG_PROTECT_CLEAR, fi->start[0] + ofs, +					fi->start[0] + ofs + len - 1, fi); +	flash_set_verbose(1); + +	return 0; +} + +static int cfi_mtd_set_erasesize(struct mtd_info *mtd, flash_info_t *fi) +{ +	int sect_size = 0; +	int sect; + +	for (sect = 0; sect < fi->sector_count; sect++) { +		if (!sect_size) { +			sect_size = flash_sector_size(fi, sect); +			continue; +		} + +		if (sect_size != flash_sector_size(fi, sect)) { +			sect_size = 0; +			break; +		} +	} + +	if (!sect_size) { +		puts("cfi-mtd: devices with multiple sector sizes are" +							"not supported\n"); +		return -EINVAL; +	} + +	mtd->erasesize = sect_size; + +	return 0; +} + +int cfi_mtd_init(void) +{ +	struct mtd_info *mtd; +	flash_info_t *fi; +	int error, i; + +	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { +		fi = &flash_info[i]; +		mtd = &cfi_mtd_info[i]; + +		memset(mtd, 0, sizeof(struct mtd_info)); + +		error = cfi_mtd_set_erasesize(mtd, fi); +		if (error) +			continue; + +		mtd->name		= CFI_MTD_DEV_NAME; +		mtd->type		= MTD_NORFLASH; +		mtd->flags		= MTD_CAP_NORFLASH; +		mtd->size		= fi->size; +		mtd->writesize		= 1; + +		mtd->erase		= cfi_mtd_erase; +		mtd->read		= cfi_mtd_read; +		mtd->write		= cfi_mtd_write; +		mtd->sync		= cfi_mtd_sync; +		mtd->lock		= cfi_mtd_lock; +		mtd->unlock		= cfi_mtd_unlock; +		mtd->priv		= fi; + +		if (add_mtd_device(mtd)) +			return -ENOMEM; +	} + +	return 0; +} diff --git a/include/flash.h b/include/flash.h index 05fa57240..6e2981c5a 100644 --- a/include/flash.h +++ b/include/flash.h @@ -86,6 +86,9 @@ typedef unsigned long flash_sect_t;  /* convert between bit value and numeric value */  #define CFI_FLASH_SHIFT_WIDTH	3 + +/* cfi-mtd device name */ +#define	CFI_MTD_DEV_NAME	"cfi-mtd"  /* Prototypes */  extern unsigned long flash_init (void); @@ -103,6 +106,11 @@ extern int flash_write (char *, ulong, ulong);  extern flash_info_t *addr2info (ulong);  extern int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt); +/* drivers/mtd/cfi_mtd.c */ +#ifdef CONFIG_FLASH_CFI_MTD +extern int cfi_mtd_init(void); +#endif +  /* board/?/flash.c */  #if defined(CONFIG_SYS_FLASH_PROTECTION)  extern int flash_real_protect(flash_info_t *info, long sector, int prot); |