mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-06 13:14:27 +00:00
140 lines
3.5 KiB
C
140 lines
3.5 KiB
C
|
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||
|
/*
|
||
|
* Copyright (c) 2018 Microsemi Corporation
|
||
|
*/
|
||
|
|
||
|
#include <linux/io.h>
|
||
|
#include "mscc_xfer.h"
|
||
|
|
||
|
#define QS_XTR_FLUSH_FLUSH GENMASK(1, 0)
|
||
|
#define QS_INJ_CTRL_GAP_SIZE(x) ((x) << 21)
|
||
|
#define QS_INJ_CTRL_EOF BIT(19)
|
||
|
#define QS_INJ_CTRL_SOF BIT(18)
|
||
|
#define QS_INJ_CTRL_VLD_BYTES(x) ((x) << 16)
|
||
|
|
||
|
#define XTR_EOF_0 ntohl(0x80000000u)
|
||
|
#define XTR_EOF_1 ntohl(0x80000001u)
|
||
|
#define XTR_EOF_2 ntohl(0x80000002u)
|
||
|
#define XTR_EOF_3 ntohl(0x80000003u)
|
||
|
#define XTR_PRUNED ntohl(0x80000004u)
|
||
|
#define XTR_ABORT ntohl(0x80000005u)
|
||
|
#define XTR_ESCAPE ntohl(0x80000006u)
|
||
|
#define XTR_NOT_READY ntohl(0x80000007u)
|
||
|
|
||
|
#define BUF_CELL_SZ 60
|
||
|
#define XTR_VALID_BYTES(x) (4 - ((x) & 3))
|
||
|
|
||
|
int mscc_send(void __iomem *regs, const unsigned long *mscc_qs_offset,
|
||
|
u32 *ifh, size_t ifh_len, u32 *buff, size_t buff_len)
|
||
|
{
|
||
|
int i, count = (buff_len + 3) / 4, last = buff_len % 4;
|
||
|
|
||
|
writel(QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF,
|
||
|
regs + mscc_qs_offset[MSCC_QS_INJ_CTRL]);
|
||
|
|
||
|
for (i = 0; i < ifh_len; i++)
|
||
|
writel(ifh[i], regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
|
||
|
|
||
|
for (i = 0; i < count; i++)
|
||
|
writel(buff[i], regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
|
||
|
|
||
|
/* Add padding */
|
||
|
while (i < (BUF_CELL_SZ / 4)) {
|
||
|
writel(0, regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
/* Indicate EOF and valid bytes in last word */
|
||
|
writel(QS_INJ_CTRL_GAP_SIZE(1) |
|
||
|
QS_INJ_CTRL_VLD_BYTES(buff_len < BUF_CELL_SZ ? 0 : last) |
|
||
|
QS_INJ_CTRL_EOF, regs + mscc_qs_offset[MSCC_QS_INJ_CTRL]);
|
||
|
|
||
|
/* Add dummy CRC */
|
||
|
writel(0, regs + mscc_qs_offset[MSCC_QS_INJ_WR]);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int mscc_recv(void __iomem *regs, const unsigned long *mscc_qs_offset,
|
||
|
u32 *rxbuf, size_t ifh_len, bool byte_swap)
|
||
|
{
|
||
|
u8 grp = 0; /* Recv everything on CPU group 0 */
|
||
|
int i, byte_cnt = 0;
|
||
|
bool eof_flag = false, pruned_flag = false, abort_flag = false;
|
||
|
|
||
|
if (!(readl(regs + mscc_qs_offset[MSCC_QS_XTR_DATA_PRESENT]) &
|
||
|
BIT(grp)))
|
||
|
return -EAGAIN;
|
||
|
|
||
|
/* skip IFH */
|
||
|
for (i = 0; i < ifh_len; i++)
|
||
|
readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
|
||
|
|
||
|
while (!eof_flag) {
|
||
|
u32 val = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
|
||
|
u32 cmp = val;
|
||
|
|
||
|
if (byte_swap)
|
||
|
cmp = ntohl(val);
|
||
|
|
||
|
switch (cmp) {
|
||
|
case XTR_NOT_READY:
|
||
|
debug("%d NOT_READY...?\n", byte_cnt);
|
||
|
break;
|
||
|
case XTR_ABORT:
|
||
|
*rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
|
||
|
abort_flag = true;
|
||
|
eof_flag = true;
|
||
|
debug("XTR_ABORT\n");
|
||
|
break;
|
||
|
case XTR_EOF_0:
|
||
|
case XTR_EOF_1:
|
||
|
case XTR_EOF_2:
|
||
|
case XTR_EOF_3:
|
||
|
byte_cnt += XTR_VALID_BYTES(val);
|
||
|
*rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
|
||
|
eof_flag = true;
|
||
|
debug("EOF\n");
|
||
|
break;
|
||
|
case XTR_PRUNED:
|
||
|
/* But get the last 4 bytes as well */
|
||
|
eof_flag = true;
|
||
|
pruned_flag = true;
|
||
|
debug("PRUNED\n");
|
||
|
/* fallthrough */
|
||
|
case XTR_ESCAPE:
|
||
|
*rxbuf = readl(regs + mscc_qs_offset[MSCC_QS_XTR_RD]);
|
||
|
byte_cnt += 4;
|
||
|
rxbuf++;
|
||
|
debug("ESCAPED\n");
|
||
|
break;
|
||
|
default:
|
||
|
*rxbuf = val;
|
||
|
byte_cnt += 4;
|
||
|
rxbuf++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (abort_flag || pruned_flag || !eof_flag) {
|
||
|
debug("Discarded frame: abort:%d pruned:%d eof:%d\n",
|
||
|
abort_flag, pruned_flag, eof_flag);
|
||
|
return -EAGAIN;
|
||
|
}
|
||
|
|
||
|
return byte_cnt;
|
||
|
}
|
||
|
|
||
|
void mscc_flush(void __iomem *regs, const unsigned long *mscc_qs_offset)
|
||
|
{
|
||
|
/* All Queues flush */
|
||
|
setbits_le32(regs + mscc_qs_offset[MSCC_QS_XTR_FLUSH],
|
||
|
QS_XTR_FLUSH_FLUSH);
|
||
|
|
||
|
/* Allow to drain */
|
||
|
mdelay(1);
|
||
|
|
||
|
/* All Queues normal */
|
||
|
clrbits_le32(regs + mscc_qs_offset[MSCC_QS_XTR_FLUSH],
|
||
|
QS_XTR_FLUSH_FLUSH);
|
||
|
}
|