mtd: spi-nor-core: Rework hwcaps selection
The spi-mem layer provides a spi_mem_supports_op() function to check
whether a specific operation is supported by the controller or not.
This is much more accurate than the hwcaps selection logic based on
SPI_{RX,TX}_ flags.
Rework the hwcaps selection logic to use spi_mem_supports_op().
To make sure the build doesn't break for boards not using CONFIG_DM_SPI,
add a simple SPI_{RX,TX}_ based hwcaps selection logic in spi-mem-nodm
similar to spi_mem_default_supports_op(). This change is only
compile-tested.
To avoid SPL size problems on the x530 board, the old hwcaps selection
is still kept around. Leaving the code in-place was getting difficult to
read and understand, so the code is restructured to have it all in one
isolated function. As a result of this, the parameter hwcaps to
spi_nor_setup() is no longer needed. Remove it.
Based on the Linux commit c76f5089796a (mtd: spi-nor: Rework hwcaps
selection for the spi-mem case, 2019-08-06)
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
			
			
This commit is contained in:
		
							parent
							
								
									8702188ce5
								
							
						
					
					
						commit
						71025f013c
					
				|  | @ -88,6 +88,15 @@ config SPI_FLASH_SFDP_SUPPORT | ||||||
| 	 SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP) | 	 SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP) | ||||||
| 	 tables as per JESD216 standard. | 	 tables as per JESD216 standard. | ||||||
| 
 | 
 | ||||||
|  | config SPI_FLASH_SMART_HWCAPS | ||||||
|  | 	bool "Smart hardware capability detection based on SPI MEM supports_op() hook" | ||||||
|  | 	default y | ||||||
|  | 	help | ||||||
|  | 	 Enable support for smart hardware capability detection based on SPI | ||||||
|  | 	 MEM supports_op() hook that lets controllers express whether they | ||||||
|  | 	 can support a type of operation in a much more refined way compared | ||||||
|  | 	 to using flags like SPI_RX_DUAL, SPI_TX_QUAD, etc. | ||||||
|  | 
 | ||||||
| config SPI_FLASH_BAR | config SPI_FLASH_BAR | ||||||
| 	bool "SPI flash Bank/Extended address register support" | 	bool "SPI flash Bank/Extended address register support" | ||||||
| 	help | 	help | ||||||
|  |  | ||||||
|  | @ -2299,6 +2299,194 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps) | ||||||
| 				  ARRAY_SIZE(hwcaps_pp2cmd)); | 				  ARRAY_SIZE(hwcaps_pp2cmd)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_SPI_FLASH_SMART_HWCAPS | ||||||
|  | /**
 | ||||||
|  |  * spi_nor_check_op - check if the operation is supported by controller | ||||||
|  |  * @nor:        pointer to a 'struct spi_nor' | ||||||
|  |  * @op:         pointer to op template to be checked | ||||||
|  |  * | ||||||
|  |  * Returns 0 if operation is supported, -ENOTSUPP otherwise. | ||||||
|  |  */ | ||||||
|  | static int spi_nor_check_op(struct spi_nor *nor, | ||||||
|  | 			    struct spi_mem_op *op) | ||||||
|  | { | ||||||
|  | 	/*
 | ||||||
|  | 	 * First test with 4 address bytes. The opcode itself might be a 3B | ||||||
|  | 	 * addressing opcode but we don't care, because SPI controller | ||||||
|  | 	 * implementation should not check the opcode, but just the sequence. | ||||||
|  | 	 */ | ||||||
|  | 	op->addr.nbytes = 4; | ||||||
|  | 	if (!spi_mem_supports_op(nor->spi, op)) { | ||||||
|  | 		if (nor->mtd.size > SZ_16M) | ||||||
|  | 			return -ENOTSUPP; | ||||||
|  | 
 | ||||||
|  | 		/* If flash size <= 16MB, 3 address bytes are sufficient */ | ||||||
|  | 		op->addr.nbytes = 3; | ||||||
|  | 		if (!spi_mem_supports_op(nor->spi, op)) | ||||||
|  | 			return -ENOTSUPP; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * spi_nor_check_readop - check if the read op is supported by controller | ||||||
|  |  * @nor:         pointer to a 'struct spi_nor' | ||||||
|  |  * @read:        pointer to op template to be checked | ||||||
|  |  * | ||||||
|  |  * Returns 0 if operation is supported, -ENOTSUPP otherwise. | ||||||
|  |  */ | ||||||
|  | static int spi_nor_check_readop(struct spi_nor *nor, | ||||||
|  | 				const struct spi_nor_read_command *read) | ||||||
|  | { | ||||||
|  | 	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 1), | ||||||
|  | 					  SPI_MEM_OP_ADDR(3, 0, 1), | ||||||
|  | 					  SPI_MEM_OP_DUMMY(0, 1), | ||||||
|  | 					  SPI_MEM_OP_DATA_IN(0, NULL, 1)); | ||||||
|  | 
 | ||||||
|  | 	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(read->proto); | ||||||
|  | 	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(read->proto); | ||||||
|  | 	op.data.buswidth = spi_nor_get_protocol_data_nbits(read->proto); | ||||||
|  | 	op.dummy.buswidth = op.addr.buswidth; | ||||||
|  | 	op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) * | ||||||
|  | 			  op.dummy.buswidth / 8; | ||||||
|  | 
 | ||||||
|  | 	return spi_nor_check_op(nor, &op); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * spi_nor_check_pp - check if the page program op is supported by controller | ||||||
|  |  * @nor:         pointer to a 'struct spi_nor' | ||||||
|  |  * @pp:          pointer to op template to be checked | ||||||
|  |  * | ||||||
|  |  * Returns 0 if operation is supported, -ENOTSUPP otherwise. | ||||||
|  |  */ | ||||||
|  | static int spi_nor_check_pp(struct spi_nor *nor, | ||||||
|  | 			    const struct spi_nor_pp_command *pp) | ||||||
|  | { | ||||||
|  | 	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 1), | ||||||
|  | 					  SPI_MEM_OP_ADDR(3, 0, 1), | ||||||
|  | 					  SPI_MEM_OP_NO_DUMMY, | ||||||
|  | 					  SPI_MEM_OP_DATA_OUT(0, NULL, 1)); | ||||||
|  | 
 | ||||||
|  | 	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(pp->proto); | ||||||
|  | 	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(pp->proto); | ||||||
|  | 	op.data.buswidth = spi_nor_get_protocol_data_nbits(pp->proto); | ||||||
|  | 
 | ||||||
|  | 	return spi_nor_check_op(nor, &op); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * spi_nor_adjust_hwcaps - Find optimal Read/Write protocol based on SPI | ||||||
|  |  *                         controller capabilities | ||||||
|  |  * @nor:        pointer to a 'struct spi_nor' | ||||||
|  |  * @params:     pointer to the 'struct spi_nor_flash_parameter' | ||||||
|  |  *              representing SPI NOR flash capabilities | ||||||
|  |  * @hwcaps:     pointer to resulting capabilities after adjusting | ||||||
|  |  *              according to controller and flash's capability | ||||||
|  |  * | ||||||
|  |  * Discard caps based on what the SPI controller actually supports (using | ||||||
|  |  * spi_mem_supports_op()). | ||||||
|  |  */ | ||||||
|  | static void | ||||||
|  | spi_nor_adjust_hwcaps(struct spi_nor *nor, | ||||||
|  | 		      const struct spi_nor_flash_parameter *params, | ||||||
|  | 		      u32 *hwcaps) | ||||||
|  | { | ||||||
|  | 	unsigned int cap; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Enable all caps by default. We will mask them after checking what's | ||||||
|  | 	 * really supported using spi_mem_supports_op(). | ||||||
|  | 	 */ | ||||||
|  | 	*hwcaps = SNOR_HWCAPS_ALL; | ||||||
|  | 
 | ||||||
|  | 	/* DTR modes are not supported yet, mask them all. */ | ||||||
|  | 	*hwcaps &= ~SNOR_HWCAPS_DTR; | ||||||
|  | 
 | ||||||
|  | 	/* X-X-X modes are not supported yet, mask them all. */ | ||||||
|  | 	*hwcaps &= ~SNOR_HWCAPS_X_X_X; | ||||||
|  | 
 | ||||||
|  | 	for (cap = 0; cap < sizeof(*hwcaps) * BITS_PER_BYTE; cap++) { | ||||||
|  | 		int rdidx, ppidx; | ||||||
|  | 
 | ||||||
|  | 		if (!(*hwcaps & BIT(cap))) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		rdidx = spi_nor_hwcaps_read2cmd(BIT(cap)); | ||||||
|  | 		if (rdidx >= 0 && | ||||||
|  | 		    spi_nor_check_readop(nor, ¶ms->reads[rdidx])) | ||||||
|  | 			*hwcaps &= ~BIT(cap); | ||||||
|  | 
 | ||||||
|  | 		ppidx = spi_nor_hwcaps_pp2cmd(BIT(cap)); | ||||||
|  | 		if (ppidx < 0) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		if (spi_nor_check_pp(nor, ¶ms->page_programs[ppidx])) | ||||||
|  | 			*hwcaps &= ~BIT(cap); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | #else | ||||||
|  | /**
 | ||||||
|  |  * spi_nor_adjust_hwcaps - Find optimal Read/Write protocol based on SPI | ||||||
|  |  *                         controller capabilities | ||||||
|  |  * @nor:        pointer to a 'struct spi_nor' | ||||||
|  |  * @params:     pointer to the 'struct spi_nor_flash_parameter' | ||||||
|  |  *              representing SPI NOR flash capabilities | ||||||
|  |  * @hwcaps:     pointer to resulting capabilities after adjusting | ||||||
|  |  *              according to controller and flash's capability | ||||||
|  |  * | ||||||
|  |  * Select caps based on what the SPI controller and SPI flash both support. | ||||||
|  |  */ | ||||||
|  | static void | ||||||
|  | spi_nor_adjust_hwcaps(struct spi_nor *nor, | ||||||
|  | 		      const struct spi_nor_flash_parameter *params, | ||||||
|  | 		      u32 *hwcaps) | ||||||
|  | { | ||||||
|  | 	struct spi_slave *spi = nor->spi; | ||||||
|  | 	u32 ignored_mask = (SNOR_HWCAPS_READ_2_2_2 | | ||||||
|  | 			    SNOR_HWCAPS_READ_4_4_4 | | ||||||
|  | 			    SNOR_HWCAPS_READ_8_8_8 | | ||||||
|  | 			    SNOR_HWCAPS_PP_4_4_4   | | ||||||
|  | 			    SNOR_HWCAPS_PP_8_8_8); | ||||||
|  | 	u32 spi_hwcaps = (SNOR_HWCAPS_READ | SNOR_HWCAPS_READ_FAST | | ||||||
|  | 			  SNOR_HWCAPS_PP); | ||||||
|  | 
 | ||||||
|  | 	/* Get the hardware capabilities the SPI controller supports. */ | ||||||
|  | 	if (spi->mode & SPI_RX_OCTAL) { | ||||||
|  | 		spi_hwcaps |= SNOR_HWCAPS_READ_1_1_8; | ||||||
|  | 
 | ||||||
|  | 		if (spi->mode & SPI_TX_OCTAL) | ||||||
|  | 			spi_hwcaps |= (SNOR_HWCAPS_READ_1_8_8 | | ||||||
|  | 					SNOR_HWCAPS_PP_1_1_8 | | ||||||
|  | 					SNOR_HWCAPS_PP_1_8_8); | ||||||
|  | 	} else if (spi->mode & SPI_RX_QUAD) { | ||||||
|  | 		spi_hwcaps |= SNOR_HWCAPS_READ_1_1_4; | ||||||
|  | 
 | ||||||
|  | 		if (spi->mode & SPI_TX_QUAD) | ||||||
|  | 			spi_hwcaps |= (SNOR_HWCAPS_READ_1_4_4 | | ||||||
|  | 					SNOR_HWCAPS_PP_1_1_4 | | ||||||
|  | 					SNOR_HWCAPS_PP_1_4_4); | ||||||
|  | 	} else if (spi->mode & SPI_RX_DUAL) { | ||||||
|  | 		spi_hwcaps |= SNOR_HWCAPS_READ_1_1_2; | ||||||
|  | 
 | ||||||
|  | 		if (spi->mode & SPI_TX_DUAL) | ||||||
|  | 			spi_hwcaps |= SNOR_HWCAPS_READ_1_2_2; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Keep only the hardware capabilities supported by both the SPI | ||||||
|  | 	 * controller and the SPI flash memory. | ||||||
|  | 	 */ | ||||||
|  | 	*hwcaps = spi_hwcaps & params->hwcaps.mask; | ||||||
|  | 	if (*hwcaps & ignored_mask) { | ||||||
|  | 		dev_dbg(nor->dev, | ||||||
|  | 			"SPI n-n-n protocols are not supported yet.\n"); | ||||||
|  | 		*hwcaps &= ~ignored_mask; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | #endif /* CONFIG_SPI_FLASH_SMART_HWCAPS */ | ||||||
|  | 
 | ||||||
| static int spi_nor_select_read(struct spi_nor *nor, | static int spi_nor_select_read(struct spi_nor *nor, | ||||||
| 			       const struct spi_nor_flash_parameter *params, | 			       const struct spi_nor_flash_parameter *params, | ||||||
| 			       u32 shared_hwcaps) | 			       u32 shared_hwcaps) | ||||||
|  | @ -2379,30 +2567,13 @@ static int spi_nor_select_erase(struct spi_nor *nor, | ||||||
| 
 | 
 | ||||||
| static int spi_nor_default_setup(struct spi_nor *nor, | static int spi_nor_default_setup(struct spi_nor *nor, | ||||||
| 				 const struct flash_info *info, | 				 const struct flash_info *info, | ||||||
| 				 const struct spi_nor_flash_parameter *params, | 				 const struct spi_nor_flash_parameter *params) | ||||||
| 				 const struct spi_nor_hwcaps *hwcaps) |  | ||||||
| { | { | ||||||
| 	u32 ignored_mask, shared_mask; | 	u32 shared_mask; | ||||||
| 	bool enable_quad_io; | 	bool enable_quad_io; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	spi_nor_adjust_hwcaps(nor, params, &shared_mask); | ||||||
| 	 * Keep only the hardware capabilities supported by both the SPI |  | ||||||
| 	 * controller and the SPI flash memory. |  | ||||||
| 	 */ |  | ||||||
| 	shared_mask = hwcaps->mask & params->hwcaps.mask; |  | ||||||
| 
 |  | ||||||
| 	/* SPI n-n-n protocols are not supported yet. */ |  | ||||||
| 	ignored_mask = (SNOR_HWCAPS_READ_2_2_2 | |  | ||||||
| 			SNOR_HWCAPS_READ_4_4_4 | |  | ||||||
| 			SNOR_HWCAPS_READ_8_8_8 | |  | ||||||
| 			SNOR_HWCAPS_PP_4_4_4 | |  | ||||||
| 			SNOR_HWCAPS_PP_8_8_8); |  | ||||||
| 	if (shared_mask & ignored_mask) { |  | ||||||
| 		dev_dbg(nor->dev, |  | ||||||
| 			"SPI n-n-n protocols are not supported yet.\n"); |  | ||||||
| 		shared_mask &= ~ignored_mask; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* Select the (Fast) Read command. */ | 	/* Select the (Fast) Read command. */ | ||||||
| 	err = spi_nor_select_read(nor, params, shared_mask); | 	err = spi_nor_select_read(nor, params, shared_mask); | ||||||
|  | @ -2440,13 +2611,12 @@ static int spi_nor_default_setup(struct spi_nor *nor, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, | static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, | ||||||
| 			 const struct spi_nor_flash_parameter *params, | 			 const struct spi_nor_flash_parameter *params) | ||||||
| 			 const struct spi_nor_hwcaps *hwcaps) |  | ||||||
| { | { | ||||||
| 	if (!nor->setup) | 	if (!nor->setup) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	return nor->setup(nor, info, params, hwcaps); | 	return nor->setup(nor, info, params); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int spi_nor_init(struct spi_nor *nor) | static int spi_nor_init(struct spi_nor *nor) | ||||||
|  | @ -2502,11 +2672,6 @@ int spi_nor_scan(struct spi_nor *nor) | ||||||
| 	struct spi_nor_flash_parameter params; | 	struct spi_nor_flash_parameter params; | ||||||
| 	const struct flash_info *info = NULL; | 	const struct flash_info *info = NULL; | ||||||
| 	struct mtd_info *mtd = &nor->mtd; | 	struct mtd_info *mtd = &nor->mtd; | ||||||
| 	struct spi_nor_hwcaps hwcaps = { |  | ||||||
| 		.mask = SNOR_HWCAPS_READ | |  | ||||||
| 			SNOR_HWCAPS_READ_FAST | |  | ||||||
| 			SNOR_HWCAPS_PP, |  | ||||||
| 	}; |  | ||||||
| 	struct spi_slave *spi = nor->spi; | 	struct spi_slave *spi = nor->spi; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
|  | @ -2521,27 +2686,6 @@ int spi_nor_scan(struct spi_nor *nor) | ||||||
| 
 | 
 | ||||||
| 	nor->setup = spi_nor_default_setup; | 	nor->setup = spi_nor_default_setup; | ||||||
| 
 | 
 | ||||||
| 	if (spi->mode & SPI_RX_OCTAL) { |  | ||||||
| 		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8; |  | ||||||
| 
 |  | ||||||
| 		if (spi->mode & SPI_TX_OCTAL) |  | ||||||
| 			hwcaps.mask |= (SNOR_HWCAPS_READ_1_8_8 | |  | ||||||
| 					SNOR_HWCAPS_PP_1_1_8 | |  | ||||||
| 					SNOR_HWCAPS_PP_1_8_8); |  | ||||||
| 	} else if (spi->mode & SPI_RX_QUAD) { |  | ||||||
| 		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; |  | ||||||
| 
 |  | ||||||
| 		if (spi->mode & SPI_TX_QUAD) |  | ||||||
| 			hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 | |  | ||||||
| 					SNOR_HWCAPS_PP_1_1_4 | |  | ||||||
| 					SNOR_HWCAPS_PP_1_4_4); |  | ||||||
| 	} else if (spi->mode & SPI_RX_DUAL) { |  | ||||||
| 		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2; |  | ||||||
| 
 |  | ||||||
| 		if (spi->mode & SPI_TX_DUAL) |  | ||||||
| 			hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	info = spi_nor_read_id(nor); | 	info = spi_nor_read_id(nor); | ||||||
| 	if (IS_ERR_OR_NULL(info)) | 	if (IS_ERR_OR_NULL(info)) | ||||||
| 		return -ENOENT; | 		return -ENOENT; | ||||||
|  | @ -2616,7 +2760,7 @@ int spi_nor_scan(struct spi_nor *nor) | ||||||
| 	 * - set the SPI protocols for register and memory accesses. | 	 * - set the SPI protocols for register and memory accesses. | ||||||
| 	 * - set the Quad Enable bit if needed (required by SPI x-y-4 protos). | 	 * - set the Quad Enable bit if needed (required by SPI x-y-4 protos). | ||||||
| 	 */ | 	 */ | ||||||
| 	ret = spi_nor_setup(nor, info, ¶ms, &hwcaps); | 	ret = spi_nor_setup(nor, info, ¶ms); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -105,3 +105,65 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | static int spi_check_buswidth_req(struct spi_slave *slave, u8 buswidth, bool tx) | ||||||
|  | { | ||||||
|  | 	u32 mode = slave->mode; | ||||||
|  | 
 | ||||||
|  | 	switch (buswidth) { | ||||||
|  | 	case 1: | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	case 2: | ||||||
|  | 		if ((tx && (mode & (SPI_TX_DUAL | SPI_TX_QUAD))) || | ||||||
|  | 		    (!tx && (mode & (SPI_RX_DUAL | SPI_RX_QUAD)))) | ||||||
|  | 			return 0; | ||||||
|  | 
 | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	case 4: | ||||||
|  | 		if ((tx && (mode & SPI_TX_QUAD)) || | ||||||
|  | 		    (!tx && (mode & SPI_RX_QUAD))) | ||||||
|  | 			return 0; | ||||||
|  | 
 | ||||||
|  | 		break; | ||||||
|  | 	case 8: | ||||||
|  | 		if ((tx && (mode & SPI_TX_OCTAL)) || | ||||||
|  | 		    (!tx && (mode & SPI_RX_OCTAL))) | ||||||
|  | 			return 0; | ||||||
|  | 
 | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	default: | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return -ENOTSUPP; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool spi_mem_supports_op(struct spi_slave *slave, const struct spi_mem_op *op) | ||||||
|  | { | ||||||
|  | 	if (spi_check_buswidth_req(slave, op->cmd.buswidth, true)) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	if (op->addr.nbytes && | ||||||
|  | 	    spi_check_buswidth_req(slave, op->addr.buswidth, true)) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	if (op->dummy.nbytes && | ||||||
|  | 	    spi_check_buswidth_req(slave, op->dummy.buswidth, true)) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	if (op->data.nbytes && | ||||||
|  | 	    spi_check_buswidth_req(slave, op->data.buswidth, | ||||||
|  | 				   op->data.dir == SPI_MEM_DATA_OUT)) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	if (op->cmd.nbytes != 1) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -312,6 +312,20 @@ struct spi_nor_hwcaps { | ||||||
| #define SNOR_HWCAPS_PP_1_8_8	BIT(21) | #define SNOR_HWCAPS_PP_1_8_8	BIT(21) | ||||||
| #define SNOR_HWCAPS_PP_8_8_8	BIT(22) | #define SNOR_HWCAPS_PP_8_8_8	BIT(22) | ||||||
| 
 | 
 | ||||||
|  | #define SNOR_HWCAPS_X_X_X	(SNOR_HWCAPS_READ_2_2_2 |	\ | ||||||
|  | 				 SNOR_HWCAPS_READ_4_4_4 |	\ | ||||||
|  | 				 SNOR_HWCAPS_READ_8_8_8 |	\ | ||||||
|  | 				 SNOR_HWCAPS_PP_4_4_4 |		\ | ||||||
|  | 				 SNOR_HWCAPS_PP_8_8_8) | ||||||
|  | 
 | ||||||
|  | #define SNOR_HWCAPS_DTR		(SNOR_HWCAPS_READ_1_1_1_DTR |	\ | ||||||
|  | 				 SNOR_HWCAPS_READ_1_2_2_DTR |	\ | ||||||
|  | 				 SNOR_HWCAPS_READ_1_4_4_DTR |	\ | ||||||
|  | 				 SNOR_HWCAPS_READ_1_8_8_DTR) | ||||||
|  | 
 | ||||||
|  | #define SNOR_HWCAPS_ALL		(SNOR_HWCAPS_READ_MASK |	\ | ||||||
|  | 				 SNOR_HWCAPS_PP_MASK) | ||||||
|  | 
 | ||||||
| struct spi_nor_read_command { | struct spi_nor_read_command { | ||||||
| 	u8			num_mode_clocks; | 	u8			num_mode_clocks; | ||||||
| 	u8			num_wait_states; | 	u8			num_wait_states; | ||||||
|  | @ -461,8 +475,7 @@ struct spi_nor { | ||||||
| 	struct spi_nor_fixups	*fixups; | 	struct spi_nor_fixups	*fixups; | ||||||
| 
 | 
 | ||||||
| 	int (*setup)(struct spi_nor *nor, const struct flash_info *info, | 	int (*setup)(struct spi_nor *nor, const struct flash_info *info, | ||||||
| 		     const struct spi_nor_flash_parameter *params, | 		     const struct spi_nor_flash_parameter *params); | ||||||
| 		     const struct spi_nor_hwcaps *hwcaps); |  | ||||||
| 	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); | 	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); | ||||||
| 	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops); | 	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops); | ||||||
| 	int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len); | 	int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue