drivers/spi: reduce confusion in the API
Julius brought up confusion about the current spi api in [1]. In order alleviate the confusion stemming from supporting x86 spi flash controllers: - Remove spi_xfer_two_vectors() which was fusing transactions to accomodate the limitations of the spi controllers themselves. - Add spi_flash_vector_helper() for the x86 spi flash controllers to utilize in validating driver/controller current assumptions. - Remove the xfer() callback in the x86 spi flash drivers which will trigger an error as these controllers can't support the api. [1] https://mail.coreboot.org/pipermail/coreboot/2018-April/086561.html Change-Id: Id88adc6ad5234c29a739d43521c5f344bb7d3217 Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: https://review.coreboot.org/25745 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
		| @@ -146,56 +146,3 @@ int spi_setup_slave(unsigned int bus, unsigned int cs, struct spi_slave *slave) | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int spi_xfer_combine_two_vectors(const struct spi_slave *slave, | ||||
| 					struct spi_op *v1, struct spi_op *v2) | ||||
| { | ||||
| 	struct spi_op op = { | ||||
| 		.dout = v1->dout, .bytesout = v1->bytesout, | ||||
| 		.din = v2->din, .bytesin = v2->bytesin, | ||||
| 	}; | ||||
| 	int ret; | ||||
|  | ||||
| 	/* | ||||
| 	 * Combine two vectors only if: | ||||
| 	 * v1 has non-NULL dout and NULL din and | ||||
| 	 * v2 has non-NULL din and NULL dout and | ||||
| 	 * | ||||
| 	 * In all other cases, do not combine the two vectors. | ||||
| 	 */ | ||||
| 	if ((!v1->dout || v1->din) || (v2->dout || !v2->din)) | ||||
| 		return -1; | ||||
|  | ||||
| 	ret = spi_xfer_single_op(slave, &op); | ||||
| 	v1->status = v2->status = op.status; | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Helper function to allow chipsets to combine two vectors if possible. This | ||||
|  * function can only handle upto 2 vectors. | ||||
|  * | ||||
|  * Two vectors are combined if first vector has a non-NULL dout and NULL din and | ||||
|  * second vector has a non-NULL din and NULL dout. Otherwise, each vector is | ||||
|  * operated upon one at a time. | ||||
|  * | ||||
|  * Returns 0 on success and non-zero on failure. | ||||
|  */ | ||||
| int spi_xfer_two_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	int ret; | ||||
|  | ||||
| 	assert (count <= 2); | ||||
|  | ||||
| 	if (count == 2) { | ||||
| 		ret = spi_xfer_combine_two_vectors(slave, &vectors[0], | ||||
| 						&vectors[1]); | ||||
|  | ||||
| 		if (!ret || (vectors[0].status != SPI_OP_NOT_EXECUTED)) | ||||
| 			return ret; | ||||
| 	} | ||||
|  | ||||
| 	return spi_xfer_vector_default(slave, vectors, count); | ||||
| } | ||||
|   | ||||
| @@ -519,3 +519,51 @@ int spi_flash_ctrlr_protect_region(const struct spi_flash *flash, | ||||
|  | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| int spi_flash_vector_helper(const struct spi_slave *slave, | ||||
| 	struct spi_op vectors[], size_t count, | ||||
| 	int (*func)(const struct spi_slave *slave, const void *dout, | ||||
| 		    size_t bytesout, void *din, size_t bytesin)) | ||||
| { | ||||
| 	int ret; | ||||
| 	void *din; | ||||
| 	size_t bytes_in; | ||||
|  | ||||
| 	if (count < 1 || count > 2) | ||||
| 		return -1; | ||||
|  | ||||
| 	/* SPI flash commands always have a command first... */ | ||||
| 	if (!vectors[0].dout || !vectors[0].bytesout) | ||||
| 		return -1; | ||||
| 	/* And not read any data during the command. */ | ||||
| 	if (vectors[0].din || vectors[0].bytesin) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (count == 2) { | ||||
| 		/* If response bytes requested ensure the buffer is valid. */ | ||||
| 		if (vectors[1].bytesin && !vectors[1].din) | ||||
| 			return -1; | ||||
| 		/* No sends can accompany a receive. */ | ||||
| 		if (vectors[1].dout || vectors[1].bytesout) | ||||
| 			return -1; | ||||
| 		din = vectors[1].din; | ||||
| 		bytes_in = vectors[1].bytesin; | ||||
| 	} else { | ||||
| 		din = NULL; | ||||
| 		bytes_in = 0; | ||||
| 	} | ||||
|  | ||||
| 	ret = func(slave, vectors[0].dout, vectors[0].bytesout, din, bytes_in); | ||||
|  | ||||
| 	if (ret) { | ||||
| 		vectors[0].status = SPI_OP_FAILURE; | ||||
| 		if (count == 2) | ||||
| 			vectors[1].status = SPI_OP_FAILURE; | ||||
| 	} else { | ||||
| 		vectors[0].status = SPI_OP_SUCCESS; | ||||
| 		if (count == 2) | ||||
| 			vectors[1].status = SPI_OP_SUCCESS; | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|   | ||||
| @@ -109,7 +109,10 @@ enum { | ||||
| }; | ||||
|  | ||||
| /*----------------------------------------------------------------------- | ||||
|  * Representation of a SPI controller. | ||||
|  * Representation of a SPI controller. Note the xfer() and xfer_vector() | ||||
|  * callbacks are meant to process full duplex transactions. If the | ||||
|  * controller cannot handle these transactions then return an error when | ||||
|  * din and dout are both set. See spi_xfer() below for more details. | ||||
|  * | ||||
|  * claim_bus:		Claim SPI bus and prepare for communication. | ||||
|  * release_bus:	Release SPI bus. | ||||
| @@ -232,6 +235,10 @@ void spi_release_bus(const struct spi_slave *slave); | ||||
|  *   din:	Pointer to a string of bytes that will be filled in. | ||||
|  *   bytesin:	How many bytes to read. | ||||
|  * | ||||
|  * Note that din and dout are transferred simulataneously in a full duplex | ||||
|  * transaction. The number of clocks within one transaction is calculated | ||||
|  * as: MAX(bytesout*8, bytesin*8). | ||||
|  * | ||||
|  *   Returns: 0 on success, not 0 on failure | ||||
|  */ | ||||
| int spi_xfer(const struct spi_slave *slave, const void *dout, size_t bytesout, | ||||
| @@ -281,23 +288,4 @@ static inline int spi_w8r8(const struct spi_slave *slave, unsigned char byte) | ||||
| 	return ret < 0 ? ret : din[1]; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Helper function to allow chipsets to combine two vectors if possible. It can | ||||
|  * only handle upto 2 vectors. | ||||
|  * | ||||
|  * This function is provided to support command-response kind of transactions | ||||
|  * expected by users like flash. Some special SPI flash controllers can handle | ||||
|  * such command-response operations in a single transaction. For these special | ||||
|  * controllers, separate command and response vectors can be combined into a | ||||
|  * single operation. | ||||
|  * | ||||
|  * Two vectors are combined if first vector has a non-NULL dout and NULL din and | ||||
|  * second vector has a non-NULL din and NULL dout. Otherwise, each vector is | ||||
|  * operated upon one at a time. | ||||
|  * | ||||
|  * Returns 0 on success and non-zero on failure. | ||||
|  */ | ||||
| int spi_xfer_two_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count); | ||||
|  | ||||
| #endif	/* _SPI_GENERIC_H_ */ | ||||
|   | ||||
| @@ -125,4 +125,18 @@ const struct spi_flash *boot_device_spi_flash(void); | ||||
| int spi_flash_ctrlr_protect_region(const struct spi_flash *flash, | ||||
| 					const struct region *region); | ||||
|  | ||||
| /* | ||||
|  * This function is provided to support spi flash command-response transactions. | ||||
|  * Only 2 vectors are supported and the 'func' is called with appropriate | ||||
|  * write and read buffers together. This can be used for chipsets that | ||||
|  * have specific spi flash controllers that don't conform to the normal | ||||
|  * spi xfer API because they are specialized controllers and not generic. | ||||
|  * | ||||
|  * Returns 0 on success and non-zero on failure. | ||||
|  */ | ||||
| int spi_flash_vector_helper(const struct spi_slave *slave, | ||||
| 	struct spi_op vectors[], size_t count, | ||||
| 	int (*func)(const struct spi_slave *slave, const void *dout, | ||||
| 		    size_t bytesout, void *din, size_t bytesin)); | ||||
|  | ||||
| #endif /* _SPI_FLASH_H_ */ | ||||
|   | ||||
| @@ -181,9 +181,14 @@ int chipset_volatile_group_end(const struct spi_flash *flash) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = SPI_FIFO_DEPTH, | ||||
| 	.flags = SPI_CNTRLR_DEDUCT_CMD_LEN | SPI_CNTRLR_DEDUCT_OPCODE_LEN, | ||||
| }; | ||||
|   | ||||
| @@ -607,9 +607,14 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = member_size(ich9_spi_regs, fdata), | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -591,9 +591,14 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = member_size(ich9_spi_regs, fdata), | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -650,9 +650,14 @@ static int spi_flash_protect(const struct spi_flash *flash, | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = member_size(ich9_spi_regs, fdata), | ||||
| 	.flash_protect = spi_flash_protect, | ||||
| }; | ||||
|   | ||||
| @@ -588,9 +588,14 @@ spi_xfer_exit: | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = member_size(ich9_spi_regs, fdata), | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -604,9 +604,14 @@ spi_xfer_exit: | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = member_size(ich9_spi_regs, fdata), | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -160,9 +160,14 @@ int chipset_volatile_group_end(const struct spi_flash *flash) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = AMD_SB_SPI_TX_LEN, | ||||
| 	.flags = SPI_CNTRLR_DEDUCT_CMD_LEN, | ||||
| }; | ||||
|   | ||||
| @@ -151,9 +151,14 @@ int chipset_volatile_group_end(const struct spi_flash *flash) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = AMD_SB_SPI_TX_LEN, | ||||
| 	.flags = SPI_CNTRLR_DEDUCT_CMD_LEN, | ||||
| }; | ||||
|   | ||||
| @@ -108,9 +108,14 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = AMD_SB_SPI_TX_LEN, | ||||
| 	.flags = SPI_CNTRLR_DEDUCT_CMD_LEN, | ||||
| }; | ||||
|   | ||||
| @@ -953,9 +953,14 @@ static int spi_flash_programmer_probe(const struct spi_slave *spi, | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = member_size(ich9_spi_regs, fdata), | ||||
| 	.flash_probe = spi_flash_programmer_probe, | ||||
| }; | ||||
|   | ||||
| @@ -719,9 +719,14 @@ spi_xfer_exit: | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int xfer_vectors(const struct spi_slave *slave, | ||||
| 			struct spi_op vectors[], size_t count) | ||||
| { | ||||
| 	return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer); | ||||
| } | ||||
|  | ||||
| static const struct spi_ctrlr spi_ctrlr = { | ||||
| 	.xfer = spi_ctrlr_xfer, | ||||
| 	.xfer_vector = spi_xfer_two_vectors, | ||||
| 	.xfer_vector = xfer_vectors, | ||||
| 	.max_xfer_size = member_size(ich10_spi_regs, fdata), | ||||
| }; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user