1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "swspi.h"
18
19 #include <assert.h>
20 #include <lib/spi/srv/dev.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <trusty/time.h>
25 #include <uapi/err.h>
26
27 #define TLOG_TAG "swspi-drv"
28 #include <trusty_log.h>
29
spi_is_bus_shared(struct spi_dev_ctx * dev)30 bool spi_is_bus_shared(struct spi_dev_ctx* dev) {
31 return dev->bus->num_devs > 1;
32 }
33
spi_dev_seq_active(struct spi_dev_ctx * dev)34 static inline bool spi_dev_seq_active(struct spi_dev_ctx* dev) {
35 return dev->cmds;
36 }
37
spi_req_exec_set_clk(struct spi_dev_ctx * dev,void * priv)38 static void spi_req_exec_set_clk(struct spi_dev_ctx* dev, void* priv) {
39 /* Not a real device. No clock to configure */
40 }
41
spi_req_set_clk(struct spi_dev_ctx * dev,uint64_t * clk_hz)42 int spi_req_set_clk(struct spi_dev_ctx* dev, uint64_t* clk_hz) {
43 assert(dev);
44 assert(clk_hz);
45
46 dev->cmds[dev->curr_cmd].exec = spi_req_exec_set_clk;
47 dev->curr_cmd++;
48 return NO_ERROR;
49 }
50
spi_req_exec_cs_assert(struct spi_dev_ctx * dev,void * priv)51 static void spi_req_exec_cs_assert(struct spi_dev_ctx* dev, void* priv) {
52 assert(dev->bus->owner == NULL);
53 /* become bus owner */
54 dev->bus->owner = dev;
55 }
56
spi_req_cs_assert(struct spi_dev_ctx * dev)57 int spi_req_cs_assert(struct spi_dev_ctx* dev) {
58 assert(spi_dev_seq_active(dev));
59 assert(dev->curr_cmd < dev->num_cmds);
60
61 dev->cmds[dev->curr_cmd].exec = spi_req_exec_cs_assert;
62 dev->curr_cmd++;
63 return NO_ERROR;
64 }
65
spi_req_exec_cs_deassert(struct spi_dev_ctx * dev,void * priv)66 static void spi_req_exec_cs_deassert(struct spi_dev_ctx* dev, void* priv) {
67 assert(dev->bus->owner == dev);
68 /* release the bus */
69 dev->bus->owner = NULL;
70 }
71
spi_req_cs_deassert(struct spi_dev_ctx * dev)72 int spi_req_cs_deassert(struct spi_dev_ctx* dev) {
73 assert(spi_dev_seq_active(dev));
74 assert(dev->curr_cmd < dev->num_cmds);
75
76 dev->cmds[dev->curr_cmd].exec = spi_req_exec_cs_deassert;
77 dev->curr_cmd++;
78 return NO_ERROR;
79 }
80
81 /* calculate an 8-bit digest of a buffer */
digest(uint8_t * buf,size_t sz)82 static uint8_t digest(uint8_t* buf, size_t sz) {
83 uint8_t digest = 0;
84
85 for (size_t i = 0; i < sz; i++) {
86 /* rotate right one bit */
87 digest = digest >> 1 | (digest & 0x1) << 7;
88 digest ^= buf[i];
89 }
90 return digest;
91 }
92
93 /* fill buffer with predefined pattern */
rand_buf(uint8_t * buf,size_t sz,uint8_t seed)94 static void rand_buf(uint8_t* buf, size_t sz, uint8_t seed) {
95 /* seed RNG */
96 srand(seed);
97
98 for (size_t i = 0; i < sz; i++) {
99 buf[i] = rand() % 0xff;
100 }
101 }
102
103 struct spi_req_xfer_args {
104 void* tx;
105 void* rx;
106 size_t len;
107 };
108
109 /*
110 * This device calculates an 8-bit digest of TX buffer, seeds rand() with that
111 * digest, fills RX with random bytes, and sends it back to us. If it's a
112 * receive-only transfer, i.e. no TX buffer, use seed 0.
113 */
spi_req_exec_xfer(struct spi_dev_ctx * dev,void * priv)114 static void spi_req_exec_xfer(struct spi_dev_ctx* dev, void* priv) {
115 struct spi_req_xfer_args* args = (struct spi_req_xfer_args*)priv;
116 void* tx = args->tx;
117 void* rx = args->rx;
118 size_t len = args->len;
119 uint8_t seed = 0;
120
121 if (dev->loopback) {
122 if (rx) {
123 if (tx) {
124 memcpy(rx, tx, len);
125 } else {
126 memset(rx, 0, len);
127 }
128 }
129 return;
130 }
131
132 if (tx) {
133 seed = digest(tx, len);
134 }
135
136 if (rx) {
137 rand_buf(rx, len, seed);
138 }
139 }
140
spi_req_xfer(struct spi_dev_ctx * dev,void * tx,void * rx,size_t len)141 int spi_req_xfer(struct spi_dev_ctx* dev, void* tx, void* rx, size_t len) {
142 assert(spi_dev_seq_active(dev));
143 assert(dev->curr_cmd < dev->num_cmds);
144
145 struct spi_req_xfer_args* args = malloc(sizeof(*args));
146 if (!args) {
147 TLOGE("failed to allocate memory for arguments for xfer requests\n");
148 return ERR_NO_MEMORY;
149 }
150 args->tx = tx;
151 args->rx = rx;
152 args->len = len;
153
154 dev->cmds[dev->curr_cmd].exec = spi_req_exec_xfer;
155 dev->cmds[dev->curr_cmd].priv = args;
156 dev->curr_cmd++;
157 return NO_ERROR;
158 }
159
spi_req_exec_delay(struct spi_dev_ctx * dev,void * priv)160 static void spi_req_exec_delay(struct spi_dev_ctx* dev, void* priv) {
161 uint64_t delay_ns = *((uint64_t*)priv);
162 trusty_nanosleep(0, 0, delay_ns);
163 }
164
spi_req_delay(struct spi_dev_ctx * dev,uint64_t delay_ns)165 int spi_req_delay(struct spi_dev_ctx* dev, uint64_t delay_ns) {
166 assert(dev);
167
168 uint64_t* arg = malloc(sizeof(*arg));
169 if (!arg) {
170 TLOGE("failed to allocate memory for delay argument\n");
171 return ERR_NO_MEMORY;
172 }
173 *arg = delay_ns;
174
175 dev->cmds[dev->curr_cmd].exec = spi_req_exec_delay;
176 dev->cmds[dev->curr_cmd].priv = arg;
177 dev->curr_cmd++;
178 return NO_ERROR;
179 }
180
spi_seq_begin(struct spi_dev_ctx * dev,size_t num_cmds)181 int spi_seq_begin(struct spi_dev_ctx* dev, size_t num_cmds) {
182 assert(!spi_dev_seq_active(dev));
183
184 /* allocate SPI sequence represented by an array of &struct spi_seq_entry */
185 dev->cmds = calloc(num_cmds, sizeof(struct spi_seq_entry));
186 if (!dev->cmds) {
187 TLOGE("failed to allocate memory for SPI sequence\n");
188 return ERR_NO_MEMORY;
189 }
190
191 dev->num_cmds = num_cmds;
192 return NO_ERROR;
193 }
194
spi_seq_free(struct spi_dev_ctx * dev)195 static void spi_seq_free(struct spi_dev_ctx* dev) {
196 for (size_t i = 0; i < dev->num_cmds; i++) {
197 void* priv = dev->cmds[i].priv;
198 if (priv) {
199 free(priv);
200 }
201 }
202 free(dev->cmds);
203 dev->cmds = NULL;
204 dev->num_cmds = 0;
205 dev->curr_cmd = 0;
206 }
207
spi_seq_commit(struct spi_dev_ctx * dev)208 int spi_seq_commit(struct spi_dev_ctx* dev) {
209 void* priv;
210 size_t i;
211
212 assert(spi_dev_seq_active(dev));
213 assert(dev->curr_cmd == dev->num_cmds);
214
215 /* iterate through SPI sequence and execute each SPI request */
216 for (i = 0; i < dev->num_cmds; i++) {
217 priv = dev->cmds[i].priv;
218 dev->cmds[i].exec(dev, priv);
219 }
220
221 spi_seq_free(dev);
222 return NO_ERROR;
223 }
224
spi_seq_abort(struct spi_dev_ctx * dev)225 void spi_seq_abort(struct spi_dev_ctx* dev) {
226 assert(spi_dev_seq_active(dev));
227 spi_seq_free(dev);
228 }
229