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