diff options
| -rw-r--r-- | README | 4 | ||||
| -rw-r--r-- | common/cmd_nand.c | 15 | ||||
| -rw-r--r-- | drivers/gpio/pca953x.c | 112 | ||||
| -rw-r--r-- | drivers/mtd/nand/atmel_nand.c | 2 | ||||
| -rw-r--r-- | drivers/mtd/nand/nand.c | 2 | ||||
| -rw-r--r-- | drivers/mtd/nand/nand_base.c | 29 | ||||
| -rw-r--r-- | drivers/mtd/nand/nand_util.c | 63 | ||||
| -rw-r--r-- | include/linux/mtd/nand.h | 4 | ||||
| -rw-r--r-- | include/nand.h | 2 | 
9 files changed, 184 insertions, 49 deletions
@@ -746,6 +746,10 @@ The following options need to be configured:  		CONFIG_PCA953X		- use NXP's PCA953X series I2C GPIO  		CONFIG_PCA953X_INFO	- enable pca953x info command +		The CONFIG_SYS_I2C_PCA953X_WIDTH option specifies a list of +		chip-ngpio pairs that tell the PCA953X driver the number of +		pins supported by a particular chip. +  		Note that if the GPIO device uses I2C, then the I2C interface  		must also be configured. See I2C Support, below. diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 678364535..7bd37de78 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -574,7 +574,15 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  							 (u_char *)addr);  			else  				ret = nand_write_skip_bad(nand, off, &rwsize, -							  (u_char *)addr); +							  (u_char *)addr, 0); +#ifdef CONFIG_CMD_NAND_YAFFS +		} else if (!strcmp(s, ".yaffs")) { +			if (read) { +				printf("Unknown nand command suffix '%s'.\n", s); +				return 1; +			} +			ret = nand_write_skip_bad(nand, off, &rwsize, (u_char *)addr, 1); +#endif  		} else if (!strcmp(s, ".oob")) {  			/* out-of-band data */  			mtd_oob_ops_t ops = { @@ -680,6 +688,11 @@ U_BOOT_CMD(  	"nand write - addr off|partition size\n"  	"    read/write 'size' bytes starting at offset 'off'\n"  	"    to/from memory address 'addr', skipping bad blocks.\n" +#ifdef CONFIG_CMD_NAND_YAFFS +	"nand write.yaffs - addr off|partition size\n" +	"    write 'size' bytes starting at offset 'off' with yaffs format\n" +	"    from memory address 'addr', skipping bad blocks.\n" +#endif  	"nand erase[.spread] [clean] [off [size]] - erase 'size' bytes "  	"from offset 'off'\n"  	"    With '.spread', erase enough for given file size, otherwise,\n" diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 6e82bd66a..359fdeea2 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -17,8 +17,8 @@   */  /* - * Driver for NXP's 4 and 8 bit I2C gpio expanders (eg pca9537, pca9557, etc) - * TODO: support additional devices with more than 8-bits GPIO + * Driver for NXP's 4, 8 and 16 bit I2C gpio expanders (eg pca9537, pca9557, + * pca9539, etc)   */  #include <common.h> @@ -38,20 +38,81 @@ enum {  	PCA953X_CMD_INVERT,  }; +#ifdef CONFIG_SYS_I2C_PCA953X_WIDTH +struct pca953x_chip_ngpio { +	uint8_t chip; +	uint8_t ngpio; +}; + +static struct pca953x_chip_ngpio pca953x_chip_ngpios[] = +    CONFIG_SYS_I2C_PCA953X_WIDTH; + +#define NUM_CHIP_GPIOS (sizeof(pca953x_chip_ngpios) / \ +			sizeof(struct pca953x_chip_ngpio)) + +/* + * Determine the number of GPIO pins supported. If we don't know we assume + * 8 pins. + */ +static int pca953x_ngpio(uint8_t chip) +{ +	int i; + +	for (i = 0; i < NUM_CHIP_GPIOS; i++) +		if (pca953x_chip_ngpios[i].chip == chip) +			return pca953x_chip_ngpios[i].ngpio; + +	return 8; +} +#else +static int pca953x_ngpio(uint8_t chip) +{ +	return 8; +} +#endif +  /*   * Modify masked bits in register   */  static int pca953x_reg_write(uint8_t chip, uint addr, uint mask, uint data)  { -	uint8_t val; +	uint8_t valb; +	uint16_t valw; -	if (i2c_read(chip, addr, 1, &val, 1)) -		return -1; +	if (pca953x_ngpio(chip) <= 8) { +		if (i2c_read(chip, addr, 1, &valb, 1)) +			return -1; + +		valb &= ~mask; +		valb |= data; + +		return i2c_write(chip, addr, 1, &valb, 1); +	} else { +		if (i2c_read(chip, addr << 1, 1, (u8*)&valw, 2)) +			return -1; -	val &= ~mask; -	val |= data; +		valw &= ~mask; +		valw |= data; -	return i2c_write(chip, addr, 1, &val, 1); +		return i2c_write(chip, addr << 1, 1, (u8*)&valw, 2); +	} +} + +static int pca953x_reg_read(uint8_t chip, uint addr, uint *data) +{ +	uint8_t valb; +	uint16_t valw; + +	if (pca953x_ngpio(chip) <= 8) { +		if (i2c_read(chip, addr, 1, &valb, 1)) +			return -1; +		*data = (int)valb; +	} else { +		if (i2c_read(chip, addr << 1, 1, (u8*)&valw, 2)) +			return -1; +		*data = (int)valw; +	} +	return 0;  }  /* @@ -86,9 +147,9 @@ int pca953x_set_dir(uint8_t chip, uint mask, uint data)   */  int pca953x_get_val(uint8_t chip)  { -	uint8_t val; +	uint val; -	if (i2c_read(chip, 0, 1, &val, 1)) +	if (pca953x_reg_read(chip, PCA953X_IN, &val) < 0)  		return -1;  	return (int)val; @@ -102,37 +163,44 @@ int pca953x_get_val(uint8_t chip)  static int pca953x_info(uint8_t chip)  {  	int i; -	uint8_t data; +	uint data; +	int nr_gpio = pca953x_ngpio(chip); +	int msb = nr_gpio - 1; -	printf("pca953x@ 0x%x:\n\n", chip); -	printf("gpio pins: 76543210\n"); -	printf("-------------------\n"); +	printf("pca953x@ 0x%x (%d pins):\n\n", chip, nr_gpio); +	printf("gpio pins: "); +	for (i = msb; i >= 0; i--) +		printf("%x", i); +	printf("\n"); +	for (i = 11 + nr_gpio; i > 0; i--) +		printf("-"); +	printf("\n"); -	if (i2c_read(chip, PCA953X_CONF, 1, &data, 1)) +	if (pca953x_reg_read(chip, PCA953X_CONF, &data) < 0)  		return -1;  	printf("conf:      "); -	for (i = 7; i >= 0; i--) +	for (i = msb; i >= 0; i--)  		printf("%c", data & (1 << i) ? 'i' : 'o');  	printf("\n"); -	if (i2c_read(chip, PCA953X_POL, 1, &data, 1)) +	if (pca953x_reg_read(chip, PCA953X_POL, &data) < 0)  		return -1;  	printf("invert:    "); -	for (i = 7; i >= 0; i--) +	for (i = msb; i >= 0; i--)  		printf("%c", data & (1 << i) ? '1' : '0');  	printf("\n"); -	if (i2c_read(chip, PCA953X_IN, 1, &data, 1)) +	if (pca953x_reg_read(chip, PCA953X_IN, &data) < 0)  		return -1;  	printf("input:     "); -	for (i = 7; i >= 0; i--) +	for (i = msb; i >= 0; i--)  		printf("%c", data & (1 << i) ? '1' : '0');  	printf("\n"); -	if (i2c_read(chip, PCA953X_OUT, 1, &data, 1)) +	if (pca953x_reg_read(chip, PCA953X_OUT, &data) < 0)  		return -1;  	printf("output:    "); -	for (i = 7; i >= 0; i--) +	for (i = msb; i >= 0; i--)  		printf("%c", data & (1 << i) ? '1' : '0');  	printf("\n"); diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index d5eb54ad8..ab8bbb3ae 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -296,7 +296,7 @@ int board_nand_init(struct nand_chip *nand)  	mtd->priv = nand;  	/* Detect NAND chips */ -	if (nand_scan_ident(mtd, 1)) { +	if (nand_scan_ident(mtd, 1, NULL)) {  		printk(KERN_WARNING "NAND Flash not found !\n");  		return -ENXIO;  	} diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c index c0e068ab7..d987f4c85 100644 --- a/drivers/mtd/nand/nand.c +++ b/drivers/mtd/nand/nand.c @@ -43,7 +43,7 @@ static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand,  			   ulong base_addr)  {  	int maxchips = CONFIG_SYS_NAND_MAX_CHIPS; -	int __attribute__((unused)) i = 0; +	static int __attribute__((unused)) i = 0;  	if (maxchips < 1)  		maxchips = 1; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5239c1fcf..3b96b0e2a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2414,10 +2414,10 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)   */  static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  						  struct nand_chip *chip, -						  int busw, int *maf_id) +						  int busw, int *maf_id, +						  const struct nand_flash_dev *type)  { -	const struct nand_flash_dev *type = NULL; -	int i, dev_id, maf_idx; +	int dev_id, maf_idx;  	int tmp_id, tmp_manf;  	/* Select the device */ @@ -2456,15 +2456,14 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  		return ERR_PTR(-ENODEV);  	} -	/* Lookup the flash id */ -	for (i = 0; nand_flash_ids[i].name != NULL; i++) { -		if (dev_id == nand_flash_ids[i].id) { -			type =  &nand_flash_ids[i]; -			break; -		} -	} +	if (!type) +		type = nand_flash_ids; + +	for (; type->name != NULL; type++) +		if (dev_id == type->id) +                        break; -	if (!type) { +	if (!type->name) {  		/* supress warning if there is no nand */  		if (*maf_id != 0x00 && *maf_id != 0xff &&  		    dev_id  != 0x00 && dev_id  != 0xff) @@ -2580,13 +2579,15 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,   * nand_scan_ident - [NAND Interface] Scan for the NAND device   * @mtd:	     MTD device structure   * @maxchips:	     Number of chips to scan for + * @table:	     Alternative NAND ID table   *   * This is the first phase of the normal nand_scan() function. It   * reads the flash ID and sets up MTD fields accordingly.   *   * The mtd->owner field must be set to the module of the caller.   */ -int nand_scan_ident(struct mtd_info *mtd, int maxchips) +int nand_scan_ident(struct mtd_info *mtd, int maxchips, +		    const struct nand_flash_dev *table)  {  	int i, busw, nand_maf_id;  	struct nand_chip *chip = mtd->priv; @@ -2598,7 +2599,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)  	nand_set_defaults(chip, busw);  	/* Read the flash type */ -	type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id); +	type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id, table);  	if (IS_ERR(type)) {  #ifndef CONFIG_SYS_NAND_QUIET_TEST @@ -2869,7 +2870,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)  {  	int ret; -	ret = nand_scan_ident(mtd, maxchips); +	ret = nand_scan_ident(mtd, maxchips, NULL);  	if (!ret)  		ret = nand_scan_tail(mtd);  	return ret; diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 22c741169..8b4f73881 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -447,17 +447,34 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length)   * @param nand  	NAND device   * @param offset	offset in flash   * @param length	buffer length - * @param buf           buffer to read from + * @param buffer        buffer to read from + * @param withoob	whether write with yaffs format   * @return		0 in case of success   */  int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, -			u_char *buffer) +			u_char *buffer, int withoob)  { -	int rval; +	int rval = 0, blocksize;  	size_t left_to_write = *length;  	u_char *p_buffer = buffer;  	int need_skip; +#ifdef CONFIG_CMD_NAND_YAFFS +	if (withoob) { +		int pages; +		pages = nand->erasesize / nand->writesize; +		blocksize = (pages * nand->oobsize) + nand->erasesize; +		if (*length % (nand->writesize + nand->oobsize)) { +			printf ("Attempt to write incomplete page" +				" in yaffs mode\n"); +			return -EINVAL; +		} +	} else +#endif +	{ +		blocksize = nand->erasesize; +	} +  	/*  	 * nand_write() handles unaligned, partial page writes.  	 * @@ -506,12 +523,44 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,  			continue;  		} -		if (left_to_write < (nand->erasesize - block_offset)) +		if (left_to_write < (blocksize - block_offset))  			write_size = left_to_write;  		else -			write_size = nand->erasesize - block_offset; +			write_size = blocksize - block_offset; + +#ifdef CONFIG_CMD_NAND_YAFFS +		if (withoob) { +			int page, pages; +			size_t pagesize = nand->writesize; +			size_t pagesize_oob = pagesize + nand->oobsize; +			struct mtd_oob_ops ops; + +			ops.len = pagesize; +			ops.ooblen = nand->oobsize; +			ops.mode = MTD_OOB_AUTO; +			ops.ooboffs = 0; + +			pages = write_size / pagesize_oob; +			for (page = 0; page < pages; page++) { +				ops.datbuf = p_buffer; +				ops.oobbuf = ops.datbuf + pagesize; + +				rval = nand->write_oob(nand, offset, &ops); +				if (!rval) +					break; + +				offset += pagesize; +				p_buffer += pagesize_oob; +			} +		} +		else +#endif +		{ +			rval = nand_write (nand, offset, &write_size, p_buffer); +			offset += write_size; +			p_buffer += write_size; +		} -		rval = nand_write (nand, offset, &write_size, p_buffer);  		if (rval != 0) {  			printf ("NAND write to offset %llx failed %d\n",  				offset, rval); @@ -520,8 +569,6 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,  		}  		left_to_write -= write_size; -		offset        += write_size; -		p_buffer      += write_size;  	}  	return 0; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 1128f5ae1..d299929ab 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -33,11 +33,13 @@  struct mtd_info; +struct nand_flash_dev;  /* Scan and identify a NAND device */  extern int nand_scan (struct mtd_info *mtd, int max_chips);  /* Separate phases of nand_scan(), allowing board driver to intervene   * and override command or ECC setup according to flash type */ -extern int nand_scan_ident(struct mtd_info *mtd, int max_chips); +extern int nand_scan_ident(struct mtd_info *mtd, int max_chips, +			   const struct nand_flash_dev *table);  extern int nand_scan_tail(struct mtd_info *mtd);  /* Free resources held by the NAND device */ diff --git a/include/nand.h b/include/nand.h index a4524113d..7459bd033 100644 --- a/include/nand.h +++ b/include/nand.h @@ -115,7 +115,7 @@ typedef struct nand_erase_options nand_erase_options_t;  int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,  		       u_char *buffer);  int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, -			u_char *buffer); +			u_char *buffer, int withoob);  int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts);  #define NAND_LOCK_STATUS_TIGHT	0x01  |