diff options
Diffstat (limited to 'drivers/mtd/spi/spi_flash.c')
| -rw-r--r-- | drivers/mtd/spi/spi_flash.c | 81 | 
1 files changed, 78 insertions, 3 deletions
| diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 00aece929..111185af1 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -8,6 +8,7 @@   */  #include <common.h> +#include <fdtdec.h>  #include <malloc.h>  #include <spi.h>  #include <spi_flash.h> @@ -15,6 +16,8 @@  #include "spi_flash_internal.h" +DECLARE_GLOBAL_DATA_PTR; +  static void spi_flash_addr(u32 addr, u8 *cmd)  {  	/* cmd[0] is actual command */ @@ -87,6 +90,9 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,  	for (actual = 0; actual < len; actual += chunk_len) {  		chunk_len = min(len - actual, page_size - byte_addr); +		if (flash->spi->max_write_size) +			chunk_len = min(chunk_len, flash->spi->max_write_size); +  		cmd[1] = page_addr >> 8;  		cmd[2] = page_addr;  		cmd[3] = byte_addr; @@ -111,8 +117,11 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,  		if (ret)  			break; -		page_addr++; -		byte_addr = 0; +		byte_addr += chunk_len; +		if (byte_addr == page_size) { +			page_addr++; +			byte_addr = 0; +		}  	}  	debug("SF: program %s %zu bytes @ %#x\n", @@ -140,6 +149,10 @@ int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,  {  	u8 cmd[5]; +	/* Handle memory-mapped SPI */ +	if (flash->memory_map) +		memcpy(data, flash->memory_map + offset, len); +  	cmd[0] = CMD_READ_ARRAY_FAST;  	spi_flash_addr(offset, cmd);  	cmd[4] = 0x00; @@ -269,6 +282,34 @@ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)  	return 0;  } +#ifdef CONFIG_OF_CONTROL +int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) +{ +	fdt_addr_t addr; +	fdt_size_t size; +	int node; + +	/* If there is no node, do nothing */ +	node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); +	if (node < 0) +		return 0; + +	addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); +	if (addr == FDT_ADDR_T_NONE) { +		debug("%s: Cannot decode address\n", __func__); +		return 0; +	} + +	if (flash->size != size) { +		debug("%s: Memory map must cover entire device\n", __func__); +		return -1; +	} +	flash->memory_map = (void *)addr; + +	return 0; +} +#endif /* CONFIG_OF_CONTROL */ +  /*   * The following table holds all device probe functions   * @@ -385,9 +426,18 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,  		goto err_manufacturer_probe;  	} +#ifdef CONFIG_OF_CONTROL +	if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { +		debug("SF: FDT decode error\n"); +		goto err_manufacturer_probe; +	} +#endif  	printf("SF: Detected %s with page size ", flash->name);  	print_size(flash->sector_size, ", total "); -	print_size(flash->size, "\n"); +	print_size(flash->size, ""); +	if (flash->memory_map) +		printf(", mapped at %p", flash->memory_map); +	puts("\n");  	spi_release_bus(spi); @@ -401,6 +451,31 @@ err_claim_bus:  	return NULL;  } +void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, +			 const char *name) +{ +	struct spi_flash *flash; +	void *ptr; + +	ptr = malloc(size); +	if (!ptr) { +		debug("SF: Failed to allocate memory\n"); +		return NULL; +	} +	memset(ptr, '\0', size); +	flash = (struct spi_flash *)(ptr + offset); + +	/* Set up some basic fields - caller will sort out sizes */ +	flash->spi = spi; +	flash->name = name; + +	flash->read = spi_flash_cmd_read_fast; +	flash->write = spi_flash_cmd_write_multi; +	flash->erase = spi_flash_cmd_erase; + +	return flash; +} +  void spi_flash_free(struct spi_flash *flash)  {  	spi_free_slave(flash->spi); |