xref: /dpdk/drivers/raw/ifpga/base/opae_spi_transaction.c (revision 68a03efeed657e6e05f281479b33b51102797e15)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2019 Intel Corporation
3  */
4 
5 #include "opae_spi.h"
6 #include "ifpga_compat.h"
7 
8 /*transaction opcodes*/
9 #define SPI_TRAN_SEQ_WRITE 0x04 /* SPI transaction sequential write */
10 #define SPI_TRAN_SEQ_READ  0x14 /* SPI transaction sequential read */
11 #define SPI_TRAN_NON_SEQ_WRITE 0x00 /* SPI transaction non-sequential write */
12 #define SPI_TRAN_NON_SEQ_READ  0x10 /* SPI transaction non-sequential read*/
13 
14 /*specail packet characters*/
15 #define SPI_PACKET_SOP     0x7a
16 #define SPI_PACKET_EOP     0x7b
17 #define SPI_PACKET_CHANNEL 0x7c
18 #define SPI_PACKET_ESC     0x7d
19 
20 /*special byte characters*/
21 #define SPI_BYTE_IDLE 0x4a
22 #define SPI_BYTE_ESC  0x4d
23 
24 #define SPI_REG_BYTES 4
25 
26 #define INIT_SPI_TRAN_HEADER(trans_type, size, address) \
27 ({ \
28 	header.trans_type = trans_type; \
29 	header.reserve = 0; \
30 	header.size = cpu_to_be16(size); \
31 	header.addr = cpu_to_be32(addr); \
32 })
33 
34 #ifdef OPAE_SPI_DEBUG
35 static void print_buffer(const char *string, void *buffer, int len)
36 {
37 	int i;
38 	unsigned char *p = buffer;
39 
40 	printf("%s print buffer, len=%d\n", string, len);
41 
42 	for (i = 0; i < len; i++)
43 		printf("%x ", *(p+i));
44 	printf("\n");
45 }
46 #else
47 static void print_buffer(const char *string, void *buffer, int len)
48 {
49 	UNUSED(string);
50 	UNUSED(buffer);
51 	UNUSED(len);
52 }
53 #endif
54 
55 static unsigned char xor_20(unsigned char val)
56 {
57 	return val^0x20;
58 }
59 
60 static void reorder_phy_data(u8 bits_per_word,
61 		void *buf, unsigned int len)
62 {
63 	unsigned int count = len / (bits_per_word/8);
64 	u32 *p;
65 
66 	if (bits_per_word == 32) {
67 		p = (u32 *)buf;
68 		while (count--) {
69 			*p = cpu_to_be32(*p);
70 			p++;
71 		}
72 	}
73 }
74 
75 enum {
76 	SPI_FOUND_SOP,
77 	SPI_FOUND_EOP,
78 	SPI_NOT_FOUND,
79 };
80 
81 static int resp_find_sop_eop(unsigned char *resp, unsigned int len,
82 		int flags)
83 {
84 	int ret = SPI_NOT_FOUND;
85 
86 	unsigned char *b = resp;
87 
88 	/* find SOP */
89 	if (flags != SPI_FOUND_SOP) {
90 		while (b < resp + len && *b != SPI_PACKET_SOP)
91 			b++;
92 
93 		if (*b != SPI_PACKET_SOP)
94 			goto done;
95 
96 		ret = SPI_FOUND_SOP;
97 	}
98 
99 	/* find EOP */
100 	while (b < resp + len && *b != SPI_PACKET_EOP)
101 		b++;
102 
103 	if (*b != SPI_PACKET_EOP)
104 		goto done;
105 
106 	ret = SPI_FOUND_EOP;
107 
108 done:
109 	return ret;
110 }
111 
112 static void phy_tx_pad(unsigned char *phy_buf, unsigned int phy_buf_len,
113 		unsigned int *aligned_len)
114 {
115 	unsigned char *p = &phy_buf[phy_buf_len - 1], *dst_p;
116 
117 	*aligned_len = IFPGA_ALIGN(phy_buf_len, 4);
118 
119 	if (*aligned_len == phy_buf_len)
120 		return;
121 
122 	dst_p = &phy_buf[*aligned_len - 1];
123 
124 	/* move EOP and bytes after EOP to the end of aligned size */
125 	while (p > phy_buf) {
126 		*dst_p = *p;
127 
128 		if (*p == SPI_PACKET_EOP)
129 			break;
130 
131 		p--;
132 		dst_p--;
133 	}
134 
135 	/* fill the hole with PHY_IDLE */
136 	while (p < dst_p)
137 		*p++ = SPI_BYTE_IDLE;
138 }
139 
140 static int byte_to_core_convert(struct spi_transaction_dev *dev,
141 		unsigned int send_len, unsigned char *send_data,
142 		unsigned int resp_len, unsigned char *resp_data,
143 		unsigned int *valid_resp_len)
144 {
145 	unsigned int i;
146 	int ret = 0;
147 	unsigned char *send_packet = dev->buffer->bytes_send;
148 	unsigned char *resp_packet = dev->buffer->bytes_resp;
149 	unsigned char *p;
150 	unsigned char current_byte;
151 	unsigned char *tx_buffer;
152 	unsigned int tx_len = 0;
153 	unsigned char *rx_buffer;
154 	unsigned int rx_len = 0;
155 	int retry = 0;
156 	int spi_flags;
157 	unsigned long timeout = msecs_to_timer_cycles(1000);
158 	unsigned long ticks;
159 	unsigned int resp_max_len = 2 * resp_len;
160 
161 	print_buffer("before bytes:", send_data, send_len);
162 
163 	p = send_packet;
164 
165 	for (i = 0; i < send_len; i++) {
166 		current_byte = send_data[i];
167 		switch (current_byte) {
168 		case SPI_BYTE_IDLE:
169 			*p++ = SPI_BYTE_ESC;
170 			*p++ = xor_20(current_byte);
171 			break;
172 		case SPI_BYTE_ESC:
173 			*p++ = SPI_BYTE_ESC;
174 			*p++ = xor_20(current_byte);
175 			break;
176 		default:
177 			*p++ = current_byte;
178 			break;
179 		}
180 	}
181 
182 	tx_len = p - send_packet;
183 
184 	print_buffer("before spi:", send_packet, tx_len);
185 
186 	phy_tx_pad(send_packet, tx_len, &tx_len);
187 	print_buffer("after pad:", send_packet, tx_len);
188 
189 	reorder_phy_data(32, send_packet, tx_len);
190 
191 	print_buffer("after order to spi:", send_packet, tx_len);
192 
193 	/* call spi */
194 	tx_buffer = send_packet;
195 	rx_buffer = resp_packet;
196 	rx_len = resp_max_len;
197 	spi_flags = SPI_NOT_FOUND;
198 
199 read_again:
200 	ret = spi_command(dev->dev, dev->chipselect, tx_len, tx_buffer,
201 			rx_len, rx_buffer);
202 	if (ret)
203 		return -EBUSY;
204 
205 	print_buffer("read from spi:", rx_buffer, rx_len);
206 
207 	/* look for SOP firstly*/
208 	ret = resp_find_sop_eop(rx_buffer, rx_len - 1, spi_flags);
209 	if (ret != SPI_FOUND_EOP) {
210 		tx_buffer = NULL;
211 		tx_len = 0;
212 		ticks = rte_get_timer_cycles();
213 		if (time_after(ticks, timeout) &&
214 				retry++ > SPI_MAX_RETRY) {
215 			dev_err(NULL, "Have retry %d, found invalid packet data\n",
216 				retry);
217 			return -EBUSY;
218 		}
219 
220 		if (ret == SPI_FOUND_SOP) {
221 			rx_buffer += rx_len;
222 			resp_max_len += rx_len;
223 		}
224 
225 		spi_flags = ret;
226 		goto read_again;
227 	}
228 
229 	print_buffer("found valid data:", resp_packet, resp_max_len);
230 
231 	/* analyze response packet */
232 	i = 0;
233 	p = resp_data;
234 	while (i < resp_max_len) {
235 		current_byte = resp_packet[i];
236 		switch (current_byte) {
237 		case SPI_BYTE_IDLE:
238 			i++;
239 			break;
240 		case SPI_BYTE_ESC:
241 			i++;
242 			current_byte = resp_packet[i];
243 			*p++ = xor_20(current_byte);
244 			i++;
245 			break;
246 		default:
247 			*p++ = current_byte;
248 			i++;
249 			break;
250 		}
251 	}
252 
253 	/* receive "4a" means the SPI is idle, not valid data */
254 	*valid_resp_len = p - resp_data;
255 	if (*valid_resp_len == 0) {
256 		dev_err(NULL, "error: repond package without valid data\n");
257 		return -EINVAL;
258 	}
259 
260 	return 0;
261 }
262 
263 static int packet_to_byte_conver(struct spi_transaction_dev *dev,
264 		unsigned int send_len, unsigned char *send_buf,
265 		unsigned int resp_len, unsigned char *resp_buf,
266 		unsigned int *valid)
267 {
268 	int ret = 0;
269 	unsigned int i;
270 	unsigned char current_byte;
271 	unsigned int resp_max_len;
272 	unsigned char *send_packet = dev->buffer->packet_send;
273 	unsigned char *resp_packet = dev->buffer->packet_resp;
274 	unsigned char *p;
275 	unsigned int valid_resp_len = 0;
276 
277 	print_buffer("before packet:", send_buf, send_len);
278 
279 	resp_max_len = 2 * resp_len + 4;
280 
281 	p = send_packet;
282 
283 	/* SOP header */
284 	*p++ = SPI_PACKET_SOP;
285 
286 	*p++ = SPI_PACKET_CHANNEL;
287 	*p++ = 0;
288 
289 	/* append the data into a packet */
290 	for (i = 0; i < send_len; i++) {
291 		current_byte = send_buf[i];
292 
293 		/* EOP for last byte */
294 		if (i == send_len - 1)
295 			*p++ = SPI_PACKET_EOP;
296 
297 		switch (current_byte) {
298 		case SPI_PACKET_SOP:
299 		case SPI_PACKET_EOP:
300 		case SPI_PACKET_CHANNEL:
301 		case SPI_PACKET_ESC:
302 			*p++ = SPI_PACKET_ESC;
303 			*p++ = xor_20(current_byte);
304 			break;
305 		default:
306 			*p++ = current_byte;
307 		}
308 	}
309 
310 	ret = byte_to_core_convert(dev, p - send_packet,
311 			send_packet, resp_max_len, resp_packet,
312 			&valid_resp_len);
313 	if (ret)
314 		return -EBUSY;
315 
316 	print_buffer("after byte conver:", resp_packet, valid_resp_len);
317 
318 	/* analyze the response packet */
319 	p = resp_buf;
320 
321 	/* look for SOP */
322 	for (i = 0; i < valid_resp_len; i++) {
323 		if (resp_packet[i] == SPI_PACKET_SOP)
324 			break;
325 	}
326 
327 	if (i == valid_resp_len) {
328 		dev_err(NULL, "error on analyze response packet 0x%x\n",
329 				resp_packet[i]);
330 		return -EINVAL;
331 	}
332 
333 	i++;
334 
335 	/* continue parsing data after SOP */
336 	while (i < valid_resp_len) {
337 		current_byte = resp_packet[i];
338 
339 		switch (current_byte) {
340 		case SPI_PACKET_ESC:
341 		case SPI_PACKET_CHANNEL:
342 		case SPI_PACKET_SOP:
343 			i++;
344 			current_byte = resp_packet[i];
345 			*p++ = xor_20(current_byte);
346 			i++;
347 			break;
348 		case SPI_PACKET_EOP:
349 			i++;
350 			current_byte = resp_packet[i];
351 			if (current_byte == SPI_PACKET_ESC ||
352 					current_byte == SPI_PACKET_CHANNEL ||
353 					current_byte == SPI_PACKET_SOP) {
354 				i++;
355 				current_byte = resp_packet[i];
356 				*p++ = xor_20(current_byte);
357 			} else
358 				*p++ = current_byte;
359 			i = valid_resp_len;
360 			break;
361 		default:
362 			*p++ = current_byte;
363 			i++;
364 		}
365 
366 	}
367 
368 	*valid = p - resp_buf;
369 
370 	print_buffer("after packet:", resp_buf, *valid);
371 
372 	return ret;
373 }
374 
375 static int do_transaction(struct spi_transaction_dev *dev, unsigned int addr,
376 		unsigned int size, unsigned char *data,
377 		unsigned int trans_type)
378 {
379 
380 	struct spi_tran_header header;
381 	unsigned char *transaction = dev->buffer->tran_send;
382 	unsigned char *response = dev->buffer->tran_resp;
383 	unsigned char *p;
384 	int ret = 0;
385 	unsigned int i;
386 	unsigned int valid_len = 0;
387 
388 	/* make transacation header */
389 	INIT_SPI_TRAN_HEADER(trans_type, size, addr);
390 
391 	/* fill the header */
392 	p = transaction;
393 	opae_memcpy(p, &header, sizeof(struct spi_tran_header));
394 	p = p + sizeof(struct spi_tran_header);
395 
396 	switch (trans_type) {
397 	case SPI_TRAN_SEQ_WRITE:
398 	case SPI_TRAN_NON_SEQ_WRITE:
399 		for (i = 0; i < size; i++)
400 			*p++ = *data++;
401 
402 		ret = packet_to_byte_conver(dev, size + HEADER_LEN,
403 				transaction, RESPONSE_LEN, response,
404 				&valid_len);
405 		if (ret)
406 			return -EBUSY;
407 
408 		/* check the result */
409 		if (size != ((unsigned int)(response[2] & 0xff) << 8 |
410 			(unsigned int)(response[3] & 0xff)))
411 			ret = -EBUSY;
412 
413 		break;
414 	case SPI_TRAN_SEQ_READ:
415 	case SPI_TRAN_NON_SEQ_READ:
416 		ret = packet_to_byte_conver(dev, HEADER_LEN,
417 				transaction, size, response,
418 				&valid_len);
419 		if (ret || valid_len != size)
420 			return -EBUSY;
421 
422 		for (i = 0; i < size; i++)
423 			*data++ = *response++;
424 
425 		ret = 0;
426 		break;
427 	}
428 
429 	return ret;
430 }
431 
432 int spi_transaction_read(struct spi_transaction_dev *dev, unsigned int addr,
433 		unsigned int size, unsigned char *data)
434 {
435 	int ret;
436 
437 	pthread_mutex_lock(dev->mutex);
438 	ret = do_transaction(dev, addr, size, data,
439 			(size > SPI_REG_BYTES) ?
440 			SPI_TRAN_SEQ_READ : SPI_TRAN_NON_SEQ_READ);
441 	pthread_mutex_unlock(dev->mutex);
442 
443 	return ret;
444 }
445 
446 int spi_transaction_write(struct spi_transaction_dev *dev, unsigned int addr,
447 		unsigned int size, unsigned char *data)
448 {
449 	int ret;
450 
451 	pthread_mutex_lock(dev->mutex);
452 	ret = do_transaction(dev, addr, size, data,
453 			(size > SPI_REG_BYTES) ?
454 			SPI_TRAN_SEQ_WRITE : SPI_TRAN_NON_SEQ_WRITE);
455 	pthread_mutex_unlock(dev->mutex);
456 
457 	return ret;
458 }
459 
460 struct spi_transaction_dev *spi_transaction_init(struct altera_spi_device *dev,
461 		int chipselect)
462 {
463 	struct spi_transaction_dev *spi_tran_dev;
464 	int ret;
465 
466 	spi_tran_dev = opae_malloc(sizeof(struct spi_transaction_dev));
467 	if (!spi_tran_dev)
468 		return NULL;
469 
470 	spi_tran_dev->dev = dev;
471 	spi_tran_dev->chipselect = chipselect;
472 
473 	spi_tran_dev->buffer = opae_malloc(sizeof(struct spi_tran_buffer));
474 	if (!spi_tran_dev->buffer)
475 		goto err;
476 
477 	ret = pthread_mutex_init(&spi_tran_dev->lock, NULL);
478 	if (ret) {
479 		dev_err(spi_tran_dev, "fail to init mutex lock\n");
480 		goto err;
481 	}
482 	if (dev->mutex) {
483 		dev_info(NULL, "use multi-process mutex in spi\n");
484 		spi_tran_dev->mutex = dev->mutex;
485 	} else {
486 		dev_info(NULL, "use multi-thread mutex in spi\n");
487 		spi_tran_dev->mutex = &spi_tran_dev->lock;
488 	}
489 
490 	return spi_tran_dev;
491 
492 err:
493 	opae_free(spi_tran_dev);
494 	return NULL;
495 }
496 
497 void spi_transaction_remove(struct spi_transaction_dev *dev)
498 {
499 	if (dev && dev->buffer)
500 		opae_free(dev->buffer);
501 	if (dev) {
502 		pthread_mutex_destroy(&dev->lock);
503 		opae_free(dev);
504 	}
505 }
506