blob: ee6bf065d3a8e28a5dc19e47854af0ade2fe7c17 [file] [log] [blame]
Horatiu Vultur2bd4c9f2019-01-31 15:30:35 +01001// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2/*
3 * Copyright (c) 2018 Microsemi Corporation
4 */
5
Tom Rini1bbf41d2023-12-14 13:16:47 -05006#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -06007#include <log.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -06008#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -06009#include <linux/delay.h>
Horatiu Vultur2bd4c9f2019-01-31 15:30:35 +010010#include <linux/io.h>
11#include "mscc_xfer.h"
12
13#define QS_XTR_FLUSH_FLUSH GENMASK(1, 0)
14#define QS_INJ_CTRL_GAP_SIZE(x) ((x) << 21)
15#define QS_INJ_CTRL_EOF BIT(19)
16#define QS_INJ_CTRL_SOF BIT(18)
17#define QS_INJ_CTRL_VLD_BYTES(x) ((x) << 16)
18
19#define XTR_EOF_0 ntohl(0x80000000u)
20#define XTR_EOF_1 ntohl(0x80000001u)
21#define XTR_EOF_2 ntohl(0x80000002u)
22#define XTR_EOF_3 ntohl(0x80000003u)
23#define XTR_PRUNED ntohl(0x80000004u)
24#define XTR_ABORT ntohl(0x80000005u)
25#define XTR_ESCAPE ntohl(0x80000006u)
26#define XTR_NOT_READY ntohl(0x80000007u)
27
28#define BUF_CELL_SZ 60
29#define XTR_VALID_BYTES(x) (4 - ((x) & 3))
30
31int mscc_send(void __iomem *regs, const unsigned long *mscc_qs_offset,
32 u32 *ifh, size_t ifh_len, u32 *buff, size_t buff_len)
33{
34 int i, count = (buff_len + 3) / 4, last = buff_len % 4;
35
36 writel(QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF,
37 regs + mscc_qs_offset[MSCC_QS_INJ_CTRL]);
38
39 for (i = 0; i < ifh_len; i++)
40 writel(ifh[i], regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
41
42 for (i = 0; i < count; i++)
43 writel(buff[i], regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
44
45 /* Add padding */
46 while (i < (BUF_CELL_SZ / 4)) {
47 writel(0, regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
48 i++;
49 }
50
51 /* Indicate EOF and valid bytes in last word */
52 writel(QS_INJ_CTRL_GAP_SIZE(1) |
53 QS_INJ_CTRL_VLD_BYTES(buff_len < BUF_CELL_SZ ? 0 : last) |
54 QS_INJ_CTRL_EOF, regs + mscc_qs_offset[MSCC_QS_INJ_CTRL]);
55
56 /* Add dummy CRC */
57 writel(0, regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
58
59 return 0;
60}
61
62int mscc_recv(void __iomem *regs, const unsigned long *mscc_qs_offset,
63 u32 *rxbuf, size_t ifh_len, bool byte_swap)
64{
65 u8 grp = 0; /* Recv everything on CPU group 0 */
66 int i, byte_cnt = 0;
67 bool eof_flag = false, pruned_flag = false, abort_flag = false;
68
69 if (!(readl(regs + mscc_qs_offset[MSCC_QS_XTR_DATA_PRESENT]) &
70 BIT(grp)))
71 return -EAGAIN;
72
73 /* skip IFH */
74 for (i = 0; i < ifh_len; i++)
75 readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
76
77 while (!eof_flag) {
78 u32 val = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
79 u32 cmp = val;
80
81 if (byte_swap)
82 cmp = ntohl(val);
83
84 switch (cmp) {
85 case XTR_NOT_READY:
86 debug("%d NOT_READY...?\n", byte_cnt);
87 break;
88 case XTR_ABORT:
89 *rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
90 abort_flag = true;
91 eof_flag = true;
92 debug("XTR_ABORT\n");
93 break;
94 case XTR_EOF_0:
95 case XTR_EOF_1:
96 case XTR_EOF_2:
97 case XTR_EOF_3:
98 byte_cnt += XTR_VALID_BYTES(val);
99 *rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
100 eof_flag = true;
101 debug("EOF\n");
102 break;
103 case XTR_PRUNED:
104 /* But get the last 4 bytes as well */
105 eof_flag = true;
106 pruned_flag = true;
107 debug("PRUNED\n");
108 /* fallthrough */
109 case XTR_ESCAPE:
110 *rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
111 byte_cnt += 4;
112 rxbuf++;
113 debug("ESCAPED\n");
114 break;
115 default:
116 *rxbuf = val;
117 byte_cnt += 4;
118 rxbuf++;
119 }
120 }
121
122 if (abort_flag || pruned_flag || !eof_flag) {
123 debug("Discarded frame: abort:%d pruned:%d eof:%d\n",
124 abort_flag, pruned_flag, eof_flag);
125 return -EAGAIN;
126 }
127
128 return byte_cnt;
129}
130
131void mscc_flush(void __iomem *regs, const unsigned long *mscc_qs_offset)
132{
133 /* All Queues flush */
134 setbits_le32(regs + mscc_qs_offset[MSCC_QS_XTR_FLUSH],
135 QS_XTR_FLUSH_FLUSH);
136
137 /* Allow to drain */
138 mdelay(1);
139
140 /* All Queues normal */
141 clrbits_le32(regs + mscc_qs_offset[MSCC_QS_XTR_FLUSH],
142 QS_XTR_FLUSH_FLUSH);
143}