xref: /aosp_15_r20/external/coreboot/src/drivers/spi/spi-generic.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <assert.h>
4 #include <commonlib/helpers.h>
5 #include <spi-generic.h>
6 #include <stddef.h>
7 #include <string.h>
8 
spi_claim_bus(const struct spi_slave * slave)9 int spi_claim_bus(const struct spi_slave *slave)
10 {
11 	const struct spi_ctrlr *ctrlr = slave->ctrlr;
12 	if (ctrlr && ctrlr->claim_bus)
13 		return ctrlr->claim_bus(slave);
14 	return 0;
15 }
16 
spi_release_bus(const struct spi_slave * slave)17 void spi_release_bus(const struct spi_slave *slave)
18 {
19 	const struct spi_ctrlr *ctrlr = slave->ctrlr;
20 	if (ctrlr && ctrlr->release_bus)
21 		ctrlr->release_bus(slave);
22 }
23 
spi_xfer_single_op(const struct spi_slave * slave,struct spi_op * op)24 static int spi_xfer_single_op(const struct spi_slave *slave,
25 			struct spi_op *op)
26 {
27 	const struct spi_ctrlr *ctrlr = slave->ctrlr;
28 	int ret;
29 
30 	if (!ctrlr || !ctrlr->xfer)
31 		return -1;
32 
33 	ret = ctrlr->xfer(slave, op->dout, op->bytesout, op->din, op->bytesin);
34 	if (ret)
35 		op->status = SPI_OP_FAILURE;
36 	else
37 		op->status = SPI_OP_SUCCESS;
38 
39 	return ret;
40 }
41 
spi_xfer_vector_default(const struct spi_slave * slave,struct spi_op vectors[],size_t count)42 static int spi_xfer_vector_default(const struct spi_slave *slave,
43 				struct spi_op vectors[], size_t count)
44 {
45 	size_t i;
46 	int ret;
47 
48 	for (i = 0; i < count; i++) {
49 		ret = spi_xfer_single_op(slave, &vectors[i]);
50 		if (ret)
51 			return ret;
52 	}
53 
54 	return 0;
55 }
56 
spi_xfer_vector(const struct spi_slave * slave,struct spi_op vectors[],size_t count)57 int spi_xfer_vector(const struct spi_slave *slave,
58 		struct spi_op vectors[], size_t count)
59 {
60 	const struct spi_ctrlr *ctrlr = slave->ctrlr;
61 
62 	if (ctrlr && ctrlr->xfer_vector)
63 		return ctrlr->xfer_vector(slave, vectors, count);
64 
65 	return spi_xfer_vector_default(slave, vectors, count);
66 }
67 
spi_xfer(const struct spi_slave * slave,const void * dout,size_t bytesout,void * din,size_t bytesin)68 int spi_xfer(const struct spi_slave *slave, const void *dout, size_t bytesout,
69 	     void *din, size_t bytesin)
70 {
71 	const struct spi_ctrlr *ctrlr = slave->ctrlr;
72 
73 	if (ctrlr && ctrlr->xfer)
74 		return ctrlr->xfer(slave, dout, bytesout, din, bytesin);
75 
76 	return -1;
77 }
78 
spi_crop_chunk(const struct spi_slave * slave,unsigned int cmd_len,unsigned int buf_len)79 unsigned int spi_crop_chunk(const struct spi_slave *slave, unsigned int cmd_len,
80 			unsigned int buf_len)
81 {
82 	const struct spi_ctrlr *ctrlr = slave->ctrlr;
83 	unsigned int ctrlr_max;
84 	bool deduct_cmd_len;
85 	bool deduct_opcode_len;
86 
87 	if (!ctrlr)
88 		return 0;
89 
90 	deduct_cmd_len = !!(ctrlr->flags & SPI_CNTRLR_DEDUCT_CMD_LEN);
91 	deduct_opcode_len = !!(ctrlr->flags & SPI_CNTRLR_DEDUCT_OPCODE_LEN);
92 	ctrlr_max = ctrlr->max_xfer_size;
93 
94 	assert(ctrlr_max != 0);
95 
96 	/* Assume opcode is always one byte and deduct it from the cmd_len
97 	   as the hardware has a separate register for the opcode. */
98 	if (deduct_opcode_len)
99 		cmd_len--;
100 
101 	/* Subtract command length from usable buffer size. If
102 	   deduct_opcode_len is set, only subtract the number command bytes
103 	   after the opcode. If the adjusted cmd_len is larger than ctrlr_max
104 	   return 0 to indicate an error. */
105 	if (deduct_cmd_len) {
106 		if (ctrlr_max >= cmd_len) {
107 			ctrlr_max -= cmd_len;
108 		} else {
109 			ctrlr_max = 0;
110 			printk(BIOS_WARNING, "%s: Command longer than buffer\n", __func__);
111 		}
112 	}
113 
114 	return MIN(ctrlr_max, buf_len);
115 }
116 
spi_init(void)117 void __weak spi_init(void)
118 {
119 	/* Default weak implementation - do nothing. */
120 }
121 
spi_setup_slave(unsigned int bus,unsigned int cs,struct spi_slave * slave)122 int spi_setup_slave(unsigned int bus, unsigned int cs, struct spi_slave *slave)
123 {
124 	size_t i;
125 
126 	memset(slave, 0, sizeof(*slave));
127 
128 	for (i = 0; i < spi_ctrlr_bus_map_count; i++) {
129 		if ((spi_ctrlr_bus_map[i].bus_start <= bus) &&
130 		    (spi_ctrlr_bus_map[i].bus_end >= bus)) {
131 			slave->ctrlr = spi_ctrlr_bus_map[i].ctrlr;
132 			break;
133 		}
134 	}
135 
136 	if (slave->ctrlr == NULL) {
137 		printk(BIOS_ERR, "Can't find SPI bus %u\n", bus);
138 		return -1;
139 	}
140 
141 	slave->bus = bus;
142 	slave->cs = cs;
143 
144 	if (slave->ctrlr->setup)
145 		return slave->ctrlr->setup(slave);
146 
147 	return 0;
148 }
149