mtd: spi: Switch to new SPI NOR framework
Switch spi_flash_* interfaces to call into new SPI NOR framework via MTD layer. Fix up sf_dataflash to work in legacy way. And update sandbox to use new interfaces/definitions Signed-off-by: Vignesh R <vigneshr@ti.com> Tested-by: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com> Tested-by: Stefan Roese <sr@denx.de> Tested-by: Horatiu Vultur <horatiu.vultur@microchip.com> Reviewed-by: Jagan Teki <jagan@openedev.com> Tested-by: Jagan Teki <jagan@amarulasolutions.com> #zynq-microzed
This commit is contained in:
		
							parent
							
								
									2ee6705be0
								
							
						
					
					
						commit
						c4e8862308
					
				|  | @ -27,6 +27,8 @@ config SPI_FLASH_SANDBOX | ||||||
| 
 | 
 | ||||||
| config SPI_FLASH | config SPI_FLASH | ||||||
| 	bool "Legacy SPI Flash Interface support" | 	bool "Legacy SPI Flash Interface support" | ||||||
|  | 	depends on SPI | ||||||
|  | 	select SPI_MEM | ||||||
| 	help | 	help | ||||||
| 	  Enable the legacy SPI flash support. This will include basic | 	  Enable the legacy SPI flash support. This will include basic | ||||||
| 	  standard support for things like probing, read / write, and | 	  standard support for things like probing, read / write, and | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ ifdef CONFIG_SPL_BUILD | ||||||
| obj-$(CONFIG_SPL_SPI_BOOT)	+= fsl_espi_spl.o | obj-$(CONFIG_SPL_SPI_BOOT)	+= fsl_espi_spl.o | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi_flash.o spi_flash_ids.o sf.o | obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi-nor-core.o | ||||||
| obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o | obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o sf.o | ||||||
| obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o | obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o | ||||||
| obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o | obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o | ||||||
|  |  | ||||||
|  | @ -92,7 +92,7 @@ struct sandbox_spi_flash { | ||||||
| 	/* The current flash status (see STAT_XXX defines above) */ | 	/* The current flash status (see STAT_XXX defines above) */ | ||||||
| 	u16 status; | 	u16 status; | ||||||
| 	/* Data describing the flash we're emulating */ | 	/* Data describing the flash we're emulating */ | ||||||
| 	const struct spi_flash_info *data; | 	const struct flash_info *data; | ||||||
| 	/* The file on disk to serv up data from */ | 	/* The file on disk to serv up data from */ | ||||||
| 	int fd; | 	int fd; | ||||||
| }; | }; | ||||||
|  | @ -122,7 +122,7 @@ static int sandbox_sf_probe(struct udevice *dev) | ||||||
| 	/* spec = idcode:file */ | 	/* spec = idcode:file */ | ||||||
| 	struct sandbox_spi_flash *sbsf = dev_get_priv(dev); | 	struct sandbox_spi_flash *sbsf = dev_get_priv(dev); | ||||||
| 	size_t len, idname_len; | 	size_t len, idname_len; | ||||||
| 	const struct spi_flash_info *data; | 	const struct flash_info *data; | ||||||
| 	struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev); | 	struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev); | ||||||
| 	struct sandbox_state *state = state_get_current(); | 	struct sandbox_state *state = state_get_current(); | ||||||
| 	struct dm_spi_slave_platdata *slave_plat; | 	struct dm_spi_slave_platdata *slave_plat; | ||||||
|  | @ -155,7 +155,7 @@ static int sandbox_sf_probe(struct udevice *dev) | ||||||
| 	idname_len = strlen(spec); | 	idname_len = strlen(spec); | ||||||
| 	debug("%s: device='%s'\n", __func__, spec); | 	debug("%s: device='%s'\n", __func__, spec); | ||||||
| 
 | 
 | ||||||
| 	for (data = spi_flash_ids; data->name; data++) { | 	for (data = spi_nor_ids; data->name; data++) { | ||||||
| 		len = strlen(data->name); | 		len = strlen(data->name); | ||||||
| 		if (idname_len != len) | 		if (idname_len != len) | ||||||
| 			continue; | 			continue; | ||||||
|  | @ -243,43 +243,43 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx, | ||||||
| 
 | 
 | ||||||
| 	sbsf->cmd = rx[0]; | 	sbsf->cmd = rx[0]; | ||||||
| 	switch (sbsf->cmd) { | 	switch (sbsf->cmd) { | ||||||
| 	case CMD_READ_ID: | 	case SPINOR_OP_RDID: | ||||||
| 		sbsf->state = SF_ID; | 		sbsf->state = SF_ID; | ||||||
| 		sbsf->cmd = SF_ID; | 		sbsf->cmd = SF_ID; | ||||||
| 		break; | 		break; | ||||||
| 	case CMD_READ_ARRAY_FAST: | 	case SPINOR_OP_READ_FAST: | ||||||
| 		sbsf->pad_addr_bytes = 1; | 		sbsf->pad_addr_bytes = 1; | ||||||
| 	case CMD_READ_ARRAY_SLOW: | 	case SPINOR_OP_READ: | ||||||
| 	case CMD_PAGE_PROGRAM: | 	case SPINOR_OP_PP: | ||||||
| 		sbsf->state = SF_ADDR; | 		sbsf->state = SF_ADDR; | ||||||
| 		break; | 		break; | ||||||
| 	case CMD_WRITE_DISABLE: | 	case SPINOR_OP_WRDI: | ||||||
| 		debug(" write disabled\n"); | 		debug(" write disabled\n"); | ||||||
| 		sbsf->status &= ~STAT_WEL; | 		sbsf->status &= ~STAT_WEL; | ||||||
| 		break; | 		break; | ||||||
| 	case CMD_READ_STATUS: | 	case SPINOR_OP_RDSR: | ||||||
| 		sbsf->state = SF_READ_STATUS; | 		sbsf->state = SF_READ_STATUS; | ||||||
| 		break; | 		break; | ||||||
| 	case CMD_READ_STATUS1: | 	case SPINOR_OP_RDSR2: | ||||||
| 		sbsf->state = SF_READ_STATUS1; | 		sbsf->state = SF_READ_STATUS1; | ||||||
| 		break; | 		break; | ||||||
| 	case CMD_WRITE_ENABLE: | 	case SPINOR_OP_WREN: | ||||||
| 		debug(" write enabled\n"); | 		debug(" write enabled\n"); | ||||||
| 		sbsf->status |= STAT_WEL; | 		sbsf->status |= STAT_WEL; | ||||||
| 		break; | 		break; | ||||||
| 	case CMD_WRITE_STATUS: | 	case SPINOR_OP_WRSR: | ||||||
| 		sbsf->state = SF_WRITE_STATUS; | 		sbsf->state = SF_WRITE_STATUS; | ||||||
| 		break; | 		break; | ||||||
| 	default: { | 	default: { | ||||||
| 		int flags = sbsf->data->flags; | 		int flags = sbsf->data->flags; | ||||||
| 
 | 
 | ||||||
| 		/* we only support erase here */ | 		/* we only support erase here */ | ||||||
| 		if (sbsf->cmd == CMD_ERASE_CHIP) { | 		if (sbsf->cmd == SPINOR_OP_CHIP_ERASE) { | ||||||
| 			sbsf->erase_size = sbsf->data->sector_size * | 			sbsf->erase_size = sbsf->data->sector_size * | ||||||
| 				sbsf->data->n_sectors; | 				sbsf->data->n_sectors; | ||||||
| 		} else if (sbsf->cmd == CMD_ERASE_4K && (flags & SECT_4K)) { | 		} else if (sbsf->cmd == SPINOR_OP_BE_4K && (flags & SECT_4K)) { | ||||||
| 			sbsf->erase_size = 4 << 10; | 			sbsf->erase_size = 4 << 10; | ||||||
| 		} else if (sbsf->cmd == CMD_ERASE_64K && !(flags & SECT_4K)) { | 		} else if (sbsf->cmd == SPINOR_OP_SE && !(flags & SECT_4K)) { | ||||||
| 			sbsf->erase_size = 64 << 10; | 			sbsf->erase_size = 64 << 10; | ||||||
| 		} else { | 		} else { | ||||||
| 			debug(" cmd unknown: %#x\n", sbsf->cmd); | 			debug(" cmd unknown: %#x\n", sbsf->cmd); | ||||||
|  | @ -380,11 +380,11 @@ static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen, | ||||||
| 				return -EIO; | 				return -EIO; | ||||||
| 			} | 			} | ||||||
| 			switch (sbsf->cmd) { | 			switch (sbsf->cmd) { | ||||||
| 			case CMD_READ_ARRAY_FAST: | 			case SPINOR_OP_READ_FAST: | ||||||
| 			case CMD_READ_ARRAY_SLOW: | 			case SPINOR_OP_READ: | ||||||
| 				sbsf->state = SF_READ; | 				sbsf->state = SF_READ; | ||||||
| 				break; | 				break; | ||||||
| 			case CMD_PAGE_PROGRAM: | 			case SPINOR_OP_PP: | ||||||
| 				sbsf->state = SF_WRITE; | 				sbsf->state = SF_WRITE; | ||||||
| 				break; | 				break; | ||||||
| 			default: | 			default: | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "sf_internal.h" | #include "sf_internal.h" | ||||||
| 
 | 
 | ||||||
|  | #define CMD_READ_ID		0x9f | ||||||
| /* reads can bypass the buffers */ | /* reads can bypass the buffers */ | ||||||
| #define OP_READ_CONTINUOUS	0xE8 | #define OP_READ_CONTINUOUS	0xE8 | ||||||
| #define OP_READ_PAGE		0xD2 | #define OP_READ_PAGE		0xD2 | ||||||
|  | @ -441,7 +442,7 @@ static int add_dataflash(struct udevice *dev, char *name, int nr_pages, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct flash_info { | struct data_flash_info { | ||||||
| 	char		*name; | 	char		*name; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -460,7 +461,7 @@ struct flash_info { | ||||||
| #define IS_POW2PS	0x0001		/* uses 2^N byte pages */ | #define IS_POW2PS	0x0001		/* uses 2^N byte pages */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct flash_info dataflash_data[] = { | static struct data_flash_info dataflash_data[] = { | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * NOTE:  chips with SUP_POW2PS (rev D and up) need two entries, | 	 * NOTE:  chips with SUP_POW2PS (rev D and up) need two entries, | ||||||
| 	 * one with IS_POW2PS and the other without.  The entry with the | 	 * one with IS_POW2PS and the other without.  The entry with the | ||||||
|  | @ -501,12 +502,12 @@ static struct flash_info dataflash_data[] = { | ||||||
| 	{ "at45db642d",  0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS}, | 	{ "at45db642d",  0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct flash_info *jedec_probe(struct spi_slave *spi) | static struct data_flash_info *jedec_probe(struct spi_slave *spi) | ||||||
| { | { | ||||||
| 	int			tmp; | 	int			tmp; | ||||||
| 	uint8_t			id[5]; | 	uint8_t			id[5]; | ||||||
| 	uint32_t		jedec; | 	uint32_t		jedec; | ||||||
| 	struct flash_info	*info; | 	struct data_flash_info	*info; | ||||||
| 	int status; | 	int status; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -583,7 +584,7 @@ static int spi_dataflash_probe(struct udevice *dev) | ||||||
| { | { | ||||||
| 	struct spi_slave *spi = dev_get_parent_priv(dev); | 	struct spi_slave *spi = dev_get_parent_priv(dev); | ||||||
| 	struct spi_flash *spi_flash; | 	struct spi_flash *spi_flash; | ||||||
| 	struct flash_info *info; | 	struct data_flash_info *info; | ||||||
| 	int status; | 	int status; | ||||||
| 
 | 
 | ||||||
| 	spi_flash = dev_get_uclass_priv(dev); | 	spi_flash = dev_get_uclass_priv(dev); | ||||||
|  |  | ||||||
|  | @ -12,142 +12,63 @@ | ||||||
| #include <linux/types.h> | #include <linux/types.h> | ||||||
| #include <linux/compiler.h> | #include <linux/compiler.h> | ||||||
| 
 | 
 | ||||||
| /* Dual SPI flash memories - see SPI_COMM_DUAL_... */ | #define SPI_NOR_MAX_ID_LEN	6 | ||||||
| enum spi_dual_flash { | #define SPI_NOR_MAX_ADDR_WIDTH	4 | ||||||
| 	SF_SINGLE_FLASH	= 0, |  | ||||||
| 	SF_DUAL_STACKED_FLASH	= BIT(0), |  | ||||||
| 	SF_DUAL_PARALLEL_FLASH	= BIT(1), |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| enum spi_nor_option_flags { | struct flash_info { | ||||||
| 	SNOR_F_SST_WR		= BIT(0), | 	char		*name; | ||||||
| 	SNOR_F_USE_FSR		= BIT(1), |  | ||||||
| 	SNOR_F_USE_UPAGE	= BIT(3), |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #define SPI_FLASH_3B_ADDR_LEN		3 |  | ||||||
| #define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN) |  | ||||||
| #define SPI_FLASH_16MB_BOUN		0x1000000 |  | ||||||
| 
 |  | ||||||
| /* CFI Manufacture ID's */ |  | ||||||
| #define SPI_FLASH_CFI_MFR_SPANSION	0x01 |  | ||||||
| #define SPI_FLASH_CFI_MFR_STMICRO	0x20 |  | ||||||
| #define SPI_FLASH_CFI_MFR_MICRON	0x2C |  | ||||||
| #define SPI_FLASH_CFI_MFR_MACRONIX	0xc2 |  | ||||||
| #define SPI_FLASH_CFI_MFR_SST		0xbf |  | ||||||
| #define SPI_FLASH_CFI_MFR_WINBOND	0xef |  | ||||||
| #define SPI_FLASH_CFI_MFR_ATMEL		0x1f |  | ||||||
| 
 |  | ||||||
| /* Erase commands */ |  | ||||||
| #define CMD_ERASE_4K			0x20 |  | ||||||
| #define CMD_ERASE_CHIP			0xc7 |  | ||||||
| #define CMD_ERASE_64K			0xd8 |  | ||||||
| 
 |  | ||||||
| /* Write commands */ |  | ||||||
| #define CMD_WRITE_STATUS		0x01 |  | ||||||
| #define CMD_PAGE_PROGRAM		0x02 |  | ||||||
| #define CMD_WRITE_DISABLE		0x04 |  | ||||||
| #define CMD_WRITE_ENABLE		0x06 |  | ||||||
| #define CMD_QUAD_PAGE_PROGRAM		0x32 |  | ||||||
| 
 |  | ||||||
| /* Read commands */ |  | ||||||
| #define CMD_READ_ARRAY_SLOW		0x03 |  | ||||||
| #define CMD_READ_ARRAY_FAST		0x0b |  | ||||||
| #define CMD_READ_DUAL_OUTPUT_FAST	0x3b |  | ||||||
| #define CMD_READ_DUAL_IO_FAST		0xbb |  | ||||||
| #define CMD_READ_QUAD_OUTPUT_FAST	0x6b |  | ||||||
| #define CMD_READ_QUAD_IO_FAST		0xeb |  | ||||||
| #define CMD_READ_ID			0x9f |  | ||||||
| #define CMD_READ_STATUS			0x05 |  | ||||||
| #define CMD_READ_STATUS1		0x35 |  | ||||||
| #define CMD_READ_CONFIG			0x35 |  | ||||||
| #define CMD_FLAG_STATUS			0x70 |  | ||||||
| 
 |  | ||||||
| /* Bank addr access commands */ |  | ||||||
| #ifdef CONFIG_SPI_FLASH_BAR |  | ||||||
| # define CMD_BANKADDR_BRWR		0x17 |  | ||||||
| # define CMD_BANKADDR_BRRD		0x16 |  | ||||||
| # define CMD_EXTNADDR_WREAR		0xC5 |  | ||||||
| # define CMD_EXTNADDR_RDEAR		0xC8 |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /* Common status */ |  | ||||||
| #define STATUS_WIP			BIT(0) |  | ||||||
| #define STATUS_QEB_WINSPAN		BIT(1) |  | ||||||
| #define STATUS_QEB_MXIC			BIT(6) |  | ||||||
| #define STATUS_PEC			BIT(7) |  | ||||||
| #define SR_BP0				BIT(2)  /* Block protect 0 */ |  | ||||||
| #define SR_BP1				BIT(3)  /* Block protect 1 */ |  | ||||||
| #define SR_BP2				BIT(4)  /* Block protect 2 */ |  | ||||||
| 
 |  | ||||||
| /* Flash timeout values */ |  | ||||||
| #define SPI_FLASH_PROG_TIMEOUT		(2 * CONFIG_SYS_HZ) |  | ||||||
| #define SPI_FLASH_PAGE_ERASE_TIMEOUT	(5 * CONFIG_SYS_HZ) |  | ||||||
| #define SPI_FLASH_SECTOR_ERASE_TIMEOUT	(10 * CONFIG_SYS_HZ) |  | ||||||
| 
 |  | ||||||
| /* SST specific */ |  | ||||||
| #ifdef CONFIG_SPI_FLASH_SST |  | ||||||
| #define SST26_CMD_READ_BPR		0x72 |  | ||||||
| #define SST26_CMD_WRITE_BPR		0x42 |  | ||||||
| 
 |  | ||||||
| #define SST26_BPR_8K_NUM		4 |  | ||||||
| #define SST26_MAX_BPR_REG_LEN		(18 + 1) |  | ||||||
| #define SST26_BOUND_REG_SIZE		((32 + SST26_BPR_8K_NUM * 8) * SZ_1K) |  | ||||||
| 
 |  | ||||||
| enum lock_ctl { |  | ||||||
| 	SST26_CTL_LOCK, |  | ||||||
| 	SST26_CTL_UNLOCK, |  | ||||||
| 	SST26_CTL_CHECK |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| # define CMD_SST_BP		0x02    /* Byte Program */ |  | ||||||
| # define CMD_SST_AAI_WP		0xAD	/* Auto Address Incr Word Program */ |  | ||||||
| 
 |  | ||||||
| int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, |  | ||||||
| 		const void *buf); |  | ||||||
| int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len, |  | ||||||
| 		const void *buf); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #define JEDEC_MFR(info)		((info)->id[0]) |  | ||||||
| #define JEDEC_ID(info)		(((info)->id[1]) << 8 | ((info)->id[2])) |  | ||||||
| #define JEDEC_EXT(info)		(((info)->id[3]) << 8 | ((info)->id[4])) |  | ||||||
| #define SPI_FLASH_MAX_ID_LEN	6 |  | ||||||
| 
 |  | ||||||
| struct spi_flash_info { |  | ||||||
| 	/* Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO]) */ |  | ||||||
| 	const char	*name; |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * This array stores the ID bytes. | 	 * This array stores the ID bytes. | ||||||
| 	 * The first three bytes are the JEDIC ID. | 	 * The first three bytes are the JEDIC ID. | ||||||
| 	 * JEDEC ID zero means "no ID" (mostly older chips). | 	 * JEDEC ID zero means "no ID" (mostly older chips). | ||||||
| 	 */ | 	 */ | ||||||
| 	u8		id[SPI_FLASH_MAX_ID_LEN]; | 	u8		id[SPI_NOR_MAX_ID_LEN]; | ||||||
| 	u8		id_len; | 	u8		id_len; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/* The size listed here is what works with SPINOR_OP_SE, which isn't
 | ||||||
| 	 * The size listed here is what works with SPINOR_OP_SE, which isn't |  | ||||||
| 	 * necessarily called a "sector" by the vendor. | 	 * necessarily called a "sector" by the vendor. | ||||||
| 	 */ | 	 */ | ||||||
| 	u32		sector_size; | 	unsigned int	sector_size; | ||||||
| 	u32		n_sectors; | 	u16		n_sectors; | ||||||
| 
 | 
 | ||||||
| 	u16		page_size; | 	u16		page_size; | ||||||
|  | 	u16		addr_width; | ||||||
| 
 | 
 | ||||||
| 	u16		flags; | 	u16		flags; | ||||||
| #define SECT_4K			BIT(0)	/* CMD_ERASE_4K works uniformly */ | #define SECT_4K			BIT(0)	/* SPINOR_OP_BE_4K works uniformly */ | ||||||
| #define E_FSR			BIT(1)	/* use flag status register for */ | #define SPI_NOR_NO_ERASE	BIT(1)	/* No erase command needed */ | ||||||
| #define SST_WR			BIT(2)	/* use SST byte/word programming */ | #define SST_WRITE		BIT(2)	/* use SST byte programming */ | ||||||
| #define WR_QPP			BIT(3)	/* use Quad Page Program */ | #define SPI_NOR_NO_FR		BIT(3)	/* Can't do fastread */ | ||||||
| #define RD_QUAD			BIT(4)	/* use Quad Read */ | #define SECT_4K_PMC		BIT(4)	/* SPINOR_OP_BE_4K_PMC works uniformly */ | ||||||
| #define RD_DUAL			BIT(5)	/* use Dual Read */ | #define SPI_NOR_DUAL_READ	BIT(5)	/* Flash supports Dual Read */ | ||||||
| #define RD_QUADIO		BIT(6)	/* use Quad IO Read */ | #define SPI_NOR_QUAD_READ	BIT(6)	/* Flash supports Quad Read */ | ||||||
| #define RD_DUALIO		BIT(7)	/* use Dual IO Read */ | #define USE_FSR			BIT(7)	/* use flag status register */ | ||||||
| #define RD_FULL			(RD_QUAD | RD_DUAL | RD_QUADIO | RD_DUALIO) | #define SPI_NOR_HAS_LOCK	BIT(8)	/* Flash supports lock/unlock via SR */ | ||||||
|  | #define SPI_NOR_HAS_TB		BIT(9)	/* | ||||||
|  | 					 * Flash SR has Top/Bottom (TB) protect | ||||||
|  | 					 * bit. Must be used with | ||||||
|  | 					 * SPI_NOR_HAS_LOCK. | ||||||
|  | 					 */ | ||||||
|  | #define	SPI_S3AN		BIT(10)	/* | ||||||
|  | 					 * Xilinx Spartan 3AN In-System Flash | ||||||
|  | 					 * (MFR cannot be used for probing | ||||||
|  | 					 * because it has the same value as | ||||||
|  | 					 * ATMEL flashes) | ||||||
|  | 					 */ | ||||||
|  | #define SPI_NOR_4B_OPCODES	BIT(11)	/* | ||||||
|  | 					 * Use dedicated 4byte address op codes | ||||||
|  | 					 * to support memory size above 128Mib. | ||||||
|  | 					 */ | ||||||
|  | #define NO_CHIP_ERASE		BIT(12) /* Chip does not support chip erase */ | ||||||
|  | #define SPI_NOR_SKIP_SFDP	BIT(13)	/* Skip parsing of SFDP tables */ | ||||||
|  | #define USE_CLSR		BIT(14)	/* use CLSR command */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| extern const struct spi_flash_info spi_flash_ids[]; | extern const struct flash_info spi_nor_ids[]; | ||||||
|  | 
 | ||||||
|  | #define JEDEC_MFR(info)	((info)->id[0]) | ||||||
|  | #define JEDEC_ID(info)		(((info)->id[1]) << 8 | ((info)->id[2])) | ||||||
| 
 | 
 | ||||||
| /* Send a single-byte command to the device and read the response */ | /* Send a single-byte command to the device and read the response */ | ||||||
| int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); | int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); | ||||||
|  | @ -167,78 +88,12 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, | ||||||
| 		const void *data, size_t data_len); | 		const void *data, size_t data_len); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Flash erase(sectors) operation, support all possible erase commands */ |  | ||||||
| int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); |  | ||||||
| 
 |  | ||||||
| /* Get software write-protect value (BP bits) */ | /* Get software write-protect value (BP bits) */ | ||||||
| int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash); | int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash); | ||||||
| 
 | 
 | ||||||
| /* Lock stmicro spi flash region */ |  | ||||||
| int stm_lock(struct spi_flash *flash, u32 ofs, size_t len); |  | ||||||
| 
 |  | ||||||
| /* Unlock stmicro spi flash region */ |  | ||||||
| int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len); |  | ||||||
| 
 |  | ||||||
| /* Check if a stmicro spi flash region is completely locked */ |  | ||||||
| int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len); |  | ||||||
| 
 |  | ||||||
| /* Enable writing on the SPI flash */ |  | ||||||
| static inline int spi_flash_cmd_write_enable(struct spi_flash *flash) |  | ||||||
| { |  | ||||||
| 	return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* Disable writing on the SPI flash */ |  | ||||||
| static inline int spi_flash_cmd_write_disable(struct spi_flash *flash) |  | ||||||
| { |  | ||||||
| 	return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * Used for spi_flash write operation |  | ||||||
|  * - SPI claim |  | ||||||
|  * - spi_flash_cmd_write_enable |  | ||||||
|  * - spi_flash_cmd_write |  | ||||||
|  * - spi_flash_wait_till_ready |  | ||||||
|  * - SPI release |  | ||||||
|  */ |  | ||||||
| int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, |  | ||||||
| 		size_t cmd_len, const void *buf, size_t buf_len); |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * Flash write operation, support all possible write commands. |  | ||||||
|  * Write the requested data out breaking it up into multiple write |  | ||||||
|  * commands as needed per the write size. |  | ||||||
|  */ |  | ||||||
| int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, |  | ||||||
| 		size_t len, const void *buf); |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * Same as spi_flash_cmd_read() except it also claims/releases the SPI |  | ||||||
|  * bus. Used as common part of the ->read() operation. |  | ||||||
|  */ |  | ||||||
| int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, |  | ||||||
| 		size_t cmd_len, void *data, size_t data_len); |  | ||||||
| 
 |  | ||||||
| /* Flash read operation, support all possible read commands */ |  | ||||||
| int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, |  | ||||||
| 		size_t len, void *data); |  | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_SPI_FLASH_MTD | #ifdef CONFIG_SPI_FLASH_MTD | ||||||
| int spi_flash_mtd_register(struct spi_flash *flash); | int spi_flash_mtd_register(struct spi_flash *flash); | ||||||
| void spi_flash_mtd_unregister(void); | void spi_flash_mtd_unregister(void); | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * spi_flash_scan - scan the SPI FLASH |  | ||||||
|  * @flash:	the spi flash structure |  | ||||||
|  * |  | ||||||
|  * The drivers can use this fuction to scan the SPI FLASH. |  | ||||||
|  * In the scanning, it will try to get all the necessary information to |  | ||||||
|  * fill the spi_flash{}. |  | ||||||
|  * |  | ||||||
|  * Return: 0 for success, others for failure. |  | ||||||
|  */ |  | ||||||
| int spi_flash_scan(struct spi_flash *flash); |  | ||||||
| 
 |  | ||||||
| #endif /* _SF_INTERNAL_H_ */ | #endif /* _SF_INTERNAL_H_ */ | ||||||
|  |  | ||||||
|  | @ -40,7 +40,7 @@ static int spi_flash_probe_slave(struct spi_flash *flash) | ||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = spi_flash_scan(flash); | 	ret = spi_nor_scan(flash); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto err_read_id; | 		goto err_read_id; | ||||||
| 
 | 
 | ||||||
|  | @ -96,32 +96,38 @@ static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len, | ||||||
| 			      void *buf) | 			      void *buf) | ||||||
| { | { | ||||||
| 	struct spi_flash *flash = dev_get_uclass_priv(dev); | 	struct spi_flash *flash = dev_get_uclass_priv(dev); | ||||||
|  | 	struct mtd_info *mtd = &flash->mtd; | ||||||
|  | 	size_t retlen; | ||||||
| 
 | 
 | ||||||
| 	return log_ret(spi_flash_cmd_read_ops(flash, offset, len, buf)); | 	return log_ret(mtd->_read(mtd, offset, len, &retlen, buf)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, | static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, | ||||||
| 			       const void *buf) | 			       const void *buf) | ||||||
| { | { | ||||||
| 	struct spi_flash *flash = dev_get_uclass_priv(dev); | 	struct spi_flash *flash = dev_get_uclass_priv(dev); | ||||||
|  | 	struct mtd_info *mtd = &flash->mtd; | ||||||
|  | 	size_t retlen; | ||||||
| 
 | 
 | ||||||
| #if defined(CONFIG_SPI_FLASH_SST) | 	return mtd->_write(mtd, offset, len, &retlen, buf); | ||||||
| 	if (flash->flags & SNOR_F_SST_WR) { |  | ||||||
| 		if (flash->spi->mode & SPI_TX_BYTE) |  | ||||||
| 			return sst_write_bp(flash, offset, len, buf); |  | ||||||
| 		else |  | ||||||
| 			return sst_write_wp(flash, offset, len, buf); |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 	return spi_flash_cmd_write_ops(flash, offset, len, buf); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) | static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) | ||||||
| { | { | ||||||
| 	struct spi_flash *flash = dev_get_uclass_priv(dev); | 	struct spi_flash *flash = dev_get_uclass_priv(dev); | ||||||
|  | 	struct mtd_info *mtd = &flash->mtd; | ||||||
|  | 	struct erase_info instr; | ||||||
| 
 | 
 | ||||||
| 	return spi_flash_cmd_erase_ops(flash, offset, len); | 	if (offset % mtd->erasesize || len % mtd->erasesize) { | ||||||
|  | 		printf("SF: Erase offset/length not multiple of erase size\n"); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	memset(&instr, 0, sizeof(instr)); | ||||||
|  | 	instr.addr = offset; | ||||||
|  | 	instr.len = len; | ||||||
|  | 
 | ||||||
|  | 	return mtd->_erase(mtd, &instr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int spi_flash_std_get_sw_write_prot(struct udevice *dev) | static int spi_flash_std_get_sw_write_prot(struct udevice *dev) | ||||||
|  |  | ||||||
|  | @ -21,6 +21,8 @@ | ||||||
| #include <spi-mem.h> | #include <spi-mem.h> | ||||||
| #include <spi.h> | #include <spi.h> | ||||||
| 
 | 
 | ||||||
|  | #include "sf_internal.h" | ||||||
|  | 
 | ||||||
| /* Define max times to check status register before we give up. */ | /* Define max times to check status register before we give up. */ | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -32,63 +34,6 @@ | ||||||
| 
 | 
 | ||||||
| #define DEFAULT_READY_WAIT_JIFFIES		(40UL * HZ) | #define DEFAULT_READY_WAIT_JIFFIES		(40UL * HZ) | ||||||
| 
 | 
 | ||||||
| #define SPI_NOR_MAX_ID_LEN	6 |  | ||||||
| #define SPI_NOR_MAX_ADDR_WIDTH	4 |  | ||||||
| 
 |  | ||||||
| struct flash_info { |  | ||||||
| 	char		*name; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * This array stores the ID bytes. |  | ||||||
| 	 * The first three bytes are the JEDIC ID. |  | ||||||
| 	 * JEDEC ID zero means "no ID" (mostly older chips). |  | ||||||
| 	 */ |  | ||||||
| 	u8		id[SPI_NOR_MAX_ID_LEN]; |  | ||||||
| 	u8		id_len; |  | ||||||
| 
 |  | ||||||
| 	/* The size listed here is what works with SPINOR_OP_SE, which isn't
 |  | ||||||
| 	 * necessarily called a "sector" by the vendor. |  | ||||||
| 	 */ |  | ||||||
| 	unsigned int	sector_size; |  | ||||||
| 	u16		n_sectors; |  | ||||||
| 
 |  | ||||||
| 	u16		page_size; |  | ||||||
| 	u16		addr_width; |  | ||||||
| 
 |  | ||||||
| 	u16		flags; |  | ||||||
| #define SECT_4K			BIT(0)	/* SPINOR_OP_BE_4K works uniformly */ |  | ||||||
| #define SPI_NOR_NO_ERASE	BIT(1)	/* No erase command needed */ |  | ||||||
| #define SST_WRITE		BIT(2)	/* use SST byte programming */ |  | ||||||
| #define SPI_NOR_NO_FR		BIT(3)	/* Can't do fastread */ |  | ||||||
| #define SECT_4K_PMC		BIT(4)	/* SPINOR_OP_BE_4K_PMC works uniformly */ |  | ||||||
| #define SPI_NOR_DUAL_READ	BIT(5)	/* Flash supports Dual Read */ |  | ||||||
| #define SPI_NOR_QUAD_READ	BIT(6)	/* Flash supports Quad Read */ |  | ||||||
| #define USE_FSR			BIT(7)	/* use flag status register */ |  | ||||||
| #define SPI_NOR_HAS_LOCK	BIT(8)	/* Flash supports lock/unlock via SR */ |  | ||||||
| #define SPI_NOR_HAS_TB		BIT(9)	/* |  | ||||||
| 					 * Flash SR has Top/Bottom (TB) protect |  | ||||||
| 					 * bit. Must be used with |  | ||||||
| 					 * SPI_NOR_HAS_LOCK. |  | ||||||
| 					 */ |  | ||||||
| #define	SPI_S3AN		BIT(10)	/* |  | ||||||
| 					 * Xilinx Spartan 3AN In-System Flash |  | ||||||
| 					 * (MFR cannot be used for probing |  | ||||||
| 					 * because it has the same value as |  | ||||||
| 					 * ATMEL flashes) |  | ||||||
| 					 */ |  | ||||||
| #define SPI_NOR_4B_OPCODES	BIT(11)	/* |  | ||||||
| 					 * Use dedicated 4byte address op codes |  | ||||||
| 					 * to support memory size above 128Mib. |  | ||||||
| 					 */ |  | ||||||
| #define NO_CHIP_ERASE		BIT(12) /* Chip does not support chip erase */ |  | ||||||
| #define SPI_NOR_SKIP_SFDP	BIT(13)	/* Skip parsing of SFDP tables */ |  | ||||||
| #define USE_CLSR		BIT(14)	/* use CLSR command */ |  | ||||||
| 
 |  | ||||||
| 	int	(*quad_enable)(struct spi_nor *nor); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #define JEDEC_MFR(info)	((info)->id[0]) |  | ||||||
| 
 |  | ||||||
| static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op | static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op | ||||||
| 		*op, void *buf) | 		*op, void *buf) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -271,9 +271,9 @@ static void _stm32_qspi_enable_mmap(struct stm32_qspi_priv *priv, | ||||||
| { | { | ||||||
| 	unsigned int ccr_reg; | 	unsigned int ccr_reg; | ||||||
| 
 | 
 | ||||||
| 	priv->command = flash->read_cmd | CMD_HAS_ADR | CMD_HAS_DATA | 	priv->command = flash->read_opcode | CMD_HAS_ADR | CMD_HAS_DATA | ||||||
| 			| CMD_HAS_DUMMY; | 			| CMD_HAS_DUMMY; | ||||||
| 	priv->dummycycles = flash->dummy_byte * 8; | 	priv->dummycycles = flash->read_dummy; | ||||||
| 
 | 
 | ||||||
| 	ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_MEM_MAP); | 	ccr_reg = _stm32_qspi_gen_ccr(priv, STM32_QSPI_CCR_MEM_MAP); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <dm.h>	/* Because we dereference struct udevice here */ | #include <dm.h>	/* Because we dereference struct udevice here */ | ||||||
| #include <linux/types.h> | #include <linux/types.h> | ||||||
|  | #include <linux/mtd/spi-nor.h> | ||||||
| 
 | 
 | ||||||
| #ifndef CONFIG_SF_DEFAULT_SPEED | #ifndef CONFIG_SF_DEFAULT_SPEED | ||||||
| # define CONFIG_SF_DEFAULT_SPEED	1000000 | # define CONFIG_SF_DEFAULT_SPEED	1000000 | ||||||
|  | @ -27,86 +28,6 @@ | ||||||
| 
 | 
 | ||||||
| struct spi_slave; | struct spi_slave; | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * struct spi_flash - SPI flash structure |  | ||||||
|  * |  | ||||||
|  * @spi:		SPI slave |  | ||||||
|  * @dev:		SPI flash device |  | ||||||
|  * @name:		Name of SPI flash |  | ||||||
|  * @dual_flash:		Indicates dual flash memories - dual stacked, parallel |  | ||||||
|  * @shift:		Flash shift useful in dual parallel |  | ||||||
|  * @flags:		Indication of spi flash flags |  | ||||||
|  * @size:		Total flash size |  | ||||||
|  * @page_size:		Write (page) size |  | ||||||
|  * @sector_size:	Sector size |  | ||||||
|  * @erase_size:		Erase size |  | ||||||
|  * @bank_read_cmd:	Bank read cmd |  | ||||||
|  * @bank_write_cmd:	Bank write cmd |  | ||||||
|  * @bank_curr:		Current flash bank |  | ||||||
|  * @erase_cmd:		Erase cmd 4K, 32K, 64K |  | ||||||
|  * @read_cmd:		Read cmd - Array Fast, Extn read and quad read. |  | ||||||
|  * @write_cmd:		Write cmd - page and quad program. |  | ||||||
|  * @dummy_byte:		Dummy cycles for read operation. |  | ||||||
|  * @memory_map:		Address of read-only SPI flash access |  | ||||||
|  * @flash_lock:		lock a region of the SPI Flash |  | ||||||
|  * @flash_unlock:	unlock a region of the SPI Flash |  | ||||||
|  * @flash_is_locked:	check if a region of the SPI Flash is completely locked |  | ||||||
|  * @read:		Flash read ops: Read len bytes at offset into buf |  | ||||||
|  *			Supported cmds: Fast Array Read |  | ||||||
|  * @write:		Flash write ops: Write len bytes from buf into offset |  | ||||||
|  *			Supported cmds: Page Program |  | ||||||
|  * @erase:		Flash erase ops: Erase len bytes from offset |  | ||||||
|  *			Supported cmds: Sector erase 4K, 32K, 64K |  | ||||||
|  * return 0 - Success, 1 - Failure |  | ||||||
|  */ |  | ||||||
| struct spi_flash { |  | ||||||
| 	struct spi_slave *spi; |  | ||||||
| #ifdef CONFIG_DM_SPI_FLASH |  | ||||||
| 	struct udevice *dev; |  | ||||||
| #endif |  | ||||||
| 	const char *name; |  | ||||||
| 	u8 dual_flash; |  | ||||||
| 	u8 shift; |  | ||||||
| 	u16 flags; |  | ||||||
| 
 |  | ||||||
| 	u32 size; |  | ||||||
| 	u32 page_size; |  | ||||||
| 	u32 sector_size; |  | ||||||
| 	u32 erase_size; |  | ||||||
| #ifdef CONFIG_SPI_FLASH_BAR |  | ||||||
| 	u8 bank_read_cmd; |  | ||||||
| 	u8 bank_write_cmd; |  | ||||||
| 	u8 bank_curr; |  | ||||||
| #endif |  | ||||||
| 	u8 erase_cmd; |  | ||||||
| 	u8 read_cmd; |  | ||||||
| 	u8 write_cmd; |  | ||||||
| 	u8 dummy_byte; |  | ||||||
| 
 |  | ||||||
| 	void *memory_map; |  | ||||||
| 
 |  | ||||||
| 	int (*flash_lock)(struct spi_flash *flash, u32 ofs, size_t len); |  | ||||||
| 	int (*flash_unlock)(struct spi_flash *flash, u32 ofs, size_t len); |  | ||||||
| 	int (*flash_is_locked)(struct spi_flash *flash, u32 ofs, size_t len); |  | ||||||
| #ifndef CONFIG_DM_SPI_FLASH |  | ||||||
| 	/*
 |  | ||||||
| 	 * These are not strictly needed for driver model, but keep them here |  | ||||||
| 	 * while the transition is in progress. |  | ||||||
| 	 * |  | ||||||
| 	 * Normally each driver would provide its own operations, but for |  | ||||||
| 	 * SPI flash most chips use the same algorithms. One approach is |  | ||||||
| 	 * to create a 'common' SPI flash device which knows how to talk |  | ||||||
| 	 * to most devices, and then allow other drivers to be used instead |  | ||||||
| 	 * if required, perhaps with a way of scanning through the list to |  | ||||||
| 	 * find the driver that matches the device. |  | ||||||
| 	 */ |  | ||||||
| 	int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf); |  | ||||||
| 	int (*write)(struct spi_flash *flash, u32 offset, size_t len, |  | ||||||
| 			const void *buf); |  | ||||||
| 	int (*erase)(struct spi_flash *flash, u32 offset, size_t len); |  | ||||||
| #endif |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct dm_spi_flash_ops { | struct dm_spi_flash_ops { | ||||||
| 	int (*read)(struct udevice *dev, u32 offset, size_t len, void *buf); | 	int (*read)(struct udevice *dev, u32 offset, size_t len, void *buf); | ||||||
| 	int (*write)(struct udevice *dev, u32 offset, size_t len, | 	int (*write)(struct udevice *dev, u32 offset, size_t len, | ||||||
|  | @ -225,19 +146,37 @@ void spi_flash_free(struct spi_flash *flash); | ||||||
| static inline int spi_flash_read(struct spi_flash *flash, u32 offset, | static inline int spi_flash_read(struct spi_flash *flash, u32 offset, | ||||||
| 		size_t len, void *buf) | 		size_t len, void *buf) | ||||||
| { | { | ||||||
| 	return flash->read(flash, offset, len, buf); | 	struct mtd_info *mtd = &flash->mtd; | ||||||
|  | 	size_t retlen; | ||||||
|  | 
 | ||||||
|  | 	return mtd->_read(mtd, offset, len, &retlen, buf); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline int spi_flash_write(struct spi_flash *flash, u32 offset, | static inline int spi_flash_write(struct spi_flash *flash, u32 offset, | ||||||
| 		size_t len, const void *buf) | 		size_t len, const void *buf) | ||||||
| { | { | ||||||
| 	return flash->write(flash, offset, len, buf); | 	struct mtd_info *mtd = &flash->mtd; | ||||||
|  | 	size_t retlen; | ||||||
|  | 
 | ||||||
|  | 	return mtd->_write(mtd, offset, len, &retlen, buf); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, | static inline int spi_flash_erase(struct spi_flash *flash, u32 offset, | ||||||
| 		size_t len) | 		size_t len) | ||||||
| { | { | ||||||
| 	return flash->erase(flash, offset, len); | 	struct mtd_info *mtd = &flash->mtd; | ||||||
|  | 	struct erase_info instr; | ||||||
|  | 
 | ||||||
|  | 	if (offset % mtd->erasesize || len % mtd->erasesize) { | ||||||
|  | 		printf("SF: Erase offset/length not multiple of erase size\n"); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	memset(&instr, 0, sizeof(instr)); | ||||||
|  | 	instr.addr = offset; | ||||||
|  | 	instr.len = len; | ||||||
|  | 
 | ||||||
|  | 	return mtd->_erase(mtd, &instr); | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue