18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
58c2ecf20Sopenharmony_ci#include <linux/bitops.h>
68c2ecf20Sopenharmony_ci#include <linux/errno.h>
78c2ecf20Sopenharmony_ci#include <linux/string.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "prestera_dsa.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_CMD		GENMASK(31, 30)
128c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_IS_TAGGED	BIT(29)
138c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_DEV_NUM		GENMASK(28, 24)
148c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_PORT_NUM	GENMASK(23, 19)
158c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_VPT		GENMASK(15, 13)
168c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_EXT_BIT		BIT(12)
178c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W0_VID		GENMASK(11, 0)
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W1_EXT_BIT		BIT(31)
208c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W1_CFI_BIT		BIT(30)
218c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W1_PORT_NUM	GENMASK(11, 10)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W2_EXT_BIT		BIT(31)
248c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W2_PORT_NUM	BIT(20)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W3_VID		GENMASK(30, 27)
278c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W3_DST_EPORT	GENMASK(23, 7)
288c2ecf20Sopenharmony_ci#define PRESTERA_DSA_W3_DEV_NUM		GENMASK(6, 0)
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define PRESTERA_DSA_VID		GENMASK(15, 12)
318c2ecf20Sopenharmony_ci#define PRESTERA_DSA_DEV_NUM		GENMASK(11, 5)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciint prestera_dsa_parse(struct prestera_dsa *dsa, const u8 *dsa_buf)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	__be32 *dsa_words = (__be32 *)dsa_buf;
368c2ecf20Sopenharmony_ci	enum prestera_dsa_cmd cmd;
378c2ecf20Sopenharmony_ci	u32 words[4];
388c2ecf20Sopenharmony_ci	u32 field;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	words[0] = ntohl(dsa_words[0]);
418c2ecf20Sopenharmony_ci	words[1] = ntohl(dsa_words[1]);
428c2ecf20Sopenharmony_ci	words[2] = ntohl(dsa_words[2]);
438c2ecf20Sopenharmony_ci	words[3] = ntohl(dsa_words[3]);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/* set the common parameters */
468c2ecf20Sopenharmony_ci	cmd = (enum prestera_dsa_cmd)FIELD_GET(PRESTERA_DSA_W0_CMD, words[0]);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/* only to CPU is supported */
498c2ecf20Sopenharmony_ci	if (unlikely(cmd != PRESTERA_DSA_CMD_TO_CPU))
508c2ecf20Sopenharmony_ci		return -EINVAL;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (FIELD_GET(PRESTERA_DSA_W0_EXT_BIT, words[0]) == 0)
538c2ecf20Sopenharmony_ci		return -EINVAL;
548c2ecf20Sopenharmony_ci	if (FIELD_GET(PRESTERA_DSA_W1_EXT_BIT, words[1]) == 0)
558c2ecf20Sopenharmony_ci		return -EINVAL;
568c2ecf20Sopenharmony_ci	if (FIELD_GET(PRESTERA_DSA_W2_EXT_BIT, words[2]) == 0)
578c2ecf20Sopenharmony_ci		return -EINVAL;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	field = FIELD_GET(PRESTERA_DSA_W3_VID, words[3]);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	dsa->vlan.is_tagged = FIELD_GET(PRESTERA_DSA_W0_IS_TAGGED, words[0]);
628c2ecf20Sopenharmony_ci	dsa->vlan.cfi_bit = FIELD_GET(PRESTERA_DSA_W1_CFI_BIT, words[1]);
638c2ecf20Sopenharmony_ci	dsa->vlan.vpt = FIELD_GET(PRESTERA_DSA_W0_VPT, words[0]);
648c2ecf20Sopenharmony_ci	dsa->vlan.vid = FIELD_GET(PRESTERA_DSA_W0_VID, words[0]);
658c2ecf20Sopenharmony_ci	dsa->vlan.vid &= ~PRESTERA_DSA_VID;
668c2ecf20Sopenharmony_ci	dsa->vlan.vid |= FIELD_PREP(PRESTERA_DSA_VID, field);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	field = FIELD_GET(PRESTERA_DSA_W3_DEV_NUM, words[3]);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	dsa->hw_dev_num = FIELD_GET(PRESTERA_DSA_W0_DEV_NUM, words[0]);
718c2ecf20Sopenharmony_ci	dsa->hw_dev_num |= FIELD_PREP(PRESTERA_DSA_DEV_NUM, field);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	dsa->port_num = (FIELD_GET(PRESTERA_DSA_W0_PORT_NUM, words[0]) << 0) |
748c2ecf20Sopenharmony_ci			(FIELD_GET(PRESTERA_DSA_W1_PORT_NUM, words[1]) << 5) |
758c2ecf20Sopenharmony_ci			(FIELD_GET(PRESTERA_DSA_W2_PORT_NUM, words[2]) << 7);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return 0;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ciint prestera_dsa_build(const struct prestera_dsa *dsa, u8 *dsa_buf)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	__be32 *dsa_words = (__be32 *)dsa_buf;
838c2ecf20Sopenharmony_ci	u32 dev_num = dsa->hw_dev_num;
848c2ecf20Sopenharmony_ci	u32 words[4] = { 0 };
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	words[0] |= FIELD_PREP(PRESTERA_DSA_W0_CMD, PRESTERA_DSA_CMD_FROM_CPU);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	words[0] |= FIELD_PREP(PRESTERA_DSA_W0_DEV_NUM, dev_num);
898c2ecf20Sopenharmony_ci	dev_num = FIELD_GET(PRESTERA_DSA_DEV_NUM, dev_num);
908c2ecf20Sopenharmony_ci	words[3] |= FIELD_PREP(PRESTERA_DSA_W3_DEV_NUM, dev_num);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	words[3] |= FIELD_PREP(PRESTERA_DSA_W3_DST_EPORT, dsa->port_num);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	words[0] |= FIELD_PREP(PRESTERA_DSA_W0_EXT_BIT, 1);
958c2ecf20Sopenharmony_ci	words[1] |= FIELD_PREP(PRESTERA_DSA_W1_EXT_BIT, 1);
968c2ecf20Sopenharmony_ci	words[2] |= FIELD_PREP(PRESTERA_DSA_W2_EXT_BIT, 1);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	dsa_words[0] = htonl(words[0]);
998c2ecf20Sopenharmony_ci	dsa_words[1] = htonl(words[1]);
1008c2ecf20Sopenharmony_ci	dsa_words[2] = htonl(words[2]);
1018c2ecf20Sopenharmony_ci	dsa_words[3] = htonl(words[3]);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
105