162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT)
262306a36Sopenharmony_ci/* Copyright 2017 Microsemi Corporation
362306a36Sopenharmony_ci * Copyright 2018-2019 NXP
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#include <linux/fsl/enetc_mdio.h>
662306a36Sopenharmony_ci#include <soc/mscc/ocelot_qsys.h>
762306a36Sopenharmony_ci#include <soc/mscc/ocelot_vcap.h>
862306a36Sopenharmony_ci#include <soc/mscc/ocelot_ana.h>
962306a36Sopenharmony_ci#include <soc/mscc/ocelot_dev.h>
1062306a36Sopenharmony_ci#include <soc/mscc/ocelot_ptp.h>
1162306a36Sopenharmony_ci#include <soc/mscc/ocelot_sys.h>
1262306a36Sopenharmony_ci#include <net/tc_act/tc_gate.h>
1362306a36Sopenharmony_ci#include <soc/mscc/ocelot.h>
1462306a36Sopenharmony_ci#include <linux/dsa/ocelot.h>
1562306a36Sopenharmony_ci#include <linux/pcs-lynx.h>
1662306a36Sopenharmony_ci#include <net/pkt_sched.h>
1762306a36Sopenharmony_ci#include <linux/iopoll.h>
1862306a36Sopenharmony_ci#include <linux/mdio.h>
1962306a36Sopenharmony_ci#include <linux/of.h>
2062306a36Sopenharmony_ci#include <linux/pci.h>
2162306a36Sopenharmony_ci#include <linux/time.h>
2262306a36Sopenharmony_ci#include "felix.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define VSC9959_NUM_PORTS		6
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define VSC9959_TAS_GCL_ENTRY_MAX	63
2762306a36Sopenharmony_ci#define VSC9959_TAS_MIN_GATE_LEN_NS	33
2862306a36Sopenharmony_ci#define VSC9959_VCAP_POLICER_BASE	63
2962306a36Sopenharmony_ci#define VSC9959_VCAP_POLICER_MAX	383
3062306a36Sopenharmony_ci#define VSC9959_SWITCH_PCI_BAR		4
3162306a36Sopenharmony_ci#define VSC9959_IMDIO_PCI_BAR		0
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define VSC9959_PORT_MODE_SERDES	(OCELOT_PORT_MODE_SGMII | \
3462306a36Sopenharmony_ci					 OCELOT_PORT_MODE_QSGMII | \
3562306a36Sopenharmony_ci					 OCELOT_PORT_MODE_1000BASEX | \
3662306a36Sopenharmony_ci					 OCELOT_PORT_MODE_2500BASEX | \
3762306a36Sopenharmony_ci					 OCELOT_PORT_MODE_USXGMII)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic const u32 vsc9959_port_modes[VSC9959_NUM_PORTS] = {
4062306a36Sopenharmony_ci	VSC9959_PORT_MODE_SERDES,
4162306a36Sopenharmony_ci	VSC9959_PORT_MODE_SERDES,
4262306a36Sopenharmony_ci	VSC9959_PORT_MODE_SERDES,
4362306a36Sopenharmony_ci	VSC9959_PORT_MODE_SERDES,
4462306a36Sopenharmony_ci	OCELOT_PORT_MODE_INTERNAL,
4562306a36Sopenharmony_ci	OCELOT_PORT_MODE_INTERNAL,
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic const u32 vsc9959_ana_regmap[] = {
4962306a36Sopenharmony_ci	REG(ANA_ADVLEARN,			0x0089a0),
5062306a36Sopenharmony_ci	REG(ANA_VLANMASK,			0x0089a4),
5162306a36Sopenharmony_ci	REG_RESERVED(ANA_PORT_B_DOMAIN),
5262306a36Sopenharmony_ci	REG(ANA_ANAGEFIL,			0x0089ac),
5362306a36Sopenharmony_ci	REG(ANA_ANEVENTS,			0x0089b0),
5462306a36Sopenharmony_ci	REG(ANA_STORMLIMIT_BURST,		0x0089b4),
5562306a36Sopenharmony_ci	REG(ANA_STORMLIMIT_CFG,			0x0089b8),
5662306a36Sopenharmony_ci	REG(ANA_ISOLATED_PORTS,			0x0089c8),
5762306a36Sopenharmony_ci	REG(ANA_COMMUNITY_PORTS,		0x0089cc),
5862306a36Sopenharmony_ci	REG(ANA_AUTOAGE,			0x0089d0),
5962306a36Sopenharmony_ci	REG(ANA_MACTOPTIONS,			0x0089d4),
6062306a36Sopenharmony_ci	REG(ANA_LEARNDISC,			0x0089d8),
6162306a36Sopenharmony_ci	REG(ANA_AGENCTRL,			0x0089dc),
6262306a36Sopenharmony_ci	REG(ANA_MIRRORPORTS,			0x0089e0),
6362306a36Sopenharmony_ci	REG(ANA_EMIRRORPORTS,			0x0089e4),
6462306a36Sopenharmony_ci	REG(ANA_FLOODING,			0x0089e8),
6562306a36Sopenharmony_ci	REG(ANA_FLOODING_IPMC,			0x008a08),
6662306a36Sopenharmony_ci	REG(ANA_SFLOW_CFG,			0x008a0c),
6762306a36Sopenharmony_ci	REG(ANA_PORT_MODE,			0x008a28),
6862306a36Sopenharmony_ci	REG(ANA_CUT_THRU_CFG,			0x008a48),
6962306a36Sopenharmony_ci	REG(ANA_PGID_PGID,			0x008400),
7062306a36Sopenharmony_ci	REG(ANA_TABLES_ANMOVED,			0x007f1c),
7162306a36Sopenharmony_ci	REG(ANA_TABLES_MACHDATA,		0x007f20),
7262306a36Sopenharmony_ci	REG(ANA_TABLES_MACLDATA,		0x007f24),
7362306a36Sopenharmony_ci	REG(ANA_TABLES_STREAMDATA,		0x007f28),
7462306a36Sopenharmony_ci	REG(ANA_TABLES_MACACCESS,		0x007f2c),
7562306a36Sopenharmony_ci	REG(ANA_TABLES_MACTINDX,		0x007f30),
7662306a36Sopenharmony_ci	REG(ANA_TABLES_VLANACCESS,		0x007f34),
7762306a36Sopenharmony_ci	REG(ANA_TABLES_VLANTIDX,		0x007f38),
7862306a36Sopenharmony_ci	REG(ANA_TABLES_ISDXACCESS,		0x007f3c),
7962306a36Sopenharmony_ci	REG(ANA_TABLES_ISDXTIDX,		0x007f40),
8062306a36Sopenharmony_ci	REG(ANA_TABLES_ENTRYLIM,		0x007f00),
8162306a36Sopenharmony_ci	REG(ANA_TABLES_PTP_ID_HIGH,		0x007f44),
8262306a36Sopenharmony_ci	REG(ANA_TABLES_PTP_ID_LOW,		0x007f48),
8362306a36Sopenharmony_ci	REG(ANA_TABLES_STREAMACCESS,		0x007f4c),
8462306a36Sopenharmony_ci	REG(ANA_TABLES_STREAMTIDX,		0x007f50),
8562306a36Sopenharmony_ci	REG(ANA_TABLES_SEQ_HISTORY,		0x007f54),
8662306a36Sopenharmony_ci	REG(ANA_TABLES_SEQ_MASK,		0x007f58),
8762306a36Sopenharmony_ci	REG(ANA_TABLES_SFID_MASK,		0x007f5c),
8862306a36Sopenharmony_ci	REG(ANA_TABLES_SFIDACCESS,		0x007f60),
8962306a36Sopenharmony_ci	REG(ANA_TABLES_SFIDTIDX,		0x007f64),
9062306a36Sopenharmony_ci	REG(ANA_MSTI_STATE,			0x008600),
9162306a36Sopenharmony_ci	REG(ANA_OAM_UPM_LM_CNT,			0x008000),
9262306a36Sopenharmony_ci	REG(ANA_SG_ACCESS_CTRL,			0x008a64),
9362306a36Sopenharmony_ci	REG(ANA_SG_CONFIG_REG_1,		0x007fb0),
9462306a36Sopenharmony_ci	REG(ANA_SG_CONFIG_REG_2,		0x007fb4),
9562306a36Sopenharmony_ci	REG(ANA_SG_CONFIG_REG_3,		0x007fb8),
9662306a36Sopenharmony_ci	REG(ANA_SG_CONFIG_REG_4,		0x007fbc),
9762306a36Sopenharmony_ci	REG(ANA_SG_CONFIG_REG_5,		0x007fc0),
9862306a36Sopenharmony_ci	REG(ANA_SG_GCL_GS_CONFIG,		0x007f80),
9962306a36Sopenharmony_ci	REG(ANA_SG_GCL_TI_CONFIG,		0x007f90),
10062306a36Sopenharmony_ci	REG(ANA_SG_STATUS_REG_1,		0x008980),
10162306a36Sopenharmony_ci	REG(ANA_SG_STATUS_REG_2,		0x008984),
10262306a36Sopenharmony_ci	REG(ANA_SG_STATUS_REG_3,		0x008988),
10362306a36Sopenharmony_ci	REG(ANA_PORT_VLAN_CFG,			0x007800),
10462306a36Sopenharmony_ci	REG(ANA_PORT_DROP_CFG,			0x007804),
10562306a36Sopenharmony_ci	REG(ANA_PORT_QOS_CFG,			0x007808),
10662306a36Sopenharmony_ci	REG(ANA_PORT_VCAP_CFG,			0x00780c),
10762306a36Sopenharmony_ci	REG(ANA_PORT_VCAP_S1_KEY_CFG,		0x007810),
10862306a36Sopenharmony_ci	REG(ANA_PORT_VCAP_S2_CFG,		0x00781c),
10962306a36Sopenharmony_ci	REG(ANA_PORT_PCP_DEI_MAP,		0x007820),
11062306a36Sopenharmony_ci	REG(ANA_PORT_CPU_FWD_CFG,		0x007860),
11162306a36Sopenharmony_ci	REG(ANA_PORT_CPU_FWD_BPDU_CFG,		0x007864),
11262306a36Sopenharmony_ci	REG(ANA_PORT_CPU_FWD_GARP_CFG,		0x007868),
11362306a36Sopenharmony_ci	REG(ANA_PORT_CPU_FWD_CCM_CFG,		0x00786c),
11462306a36Sopenharmony_ci	REG(ANA_PORT_PORT_CFG,			0x007870),
11562306a36Sopenharmony_ci	REG(ANA_PORT_POL_CFG,			0x007874),
11662306a36Sopenharmony_ci	REG(ANA_PORT_PTP_CFG,			0x007878),
11762306a36Sopenharmony_ci	REG(ANA_PORT_PTP_DLY1_CFG,		0x00787c),
11862306a36Sopenharmony_ci	REG(ANA_PORT_PTP_DLY2_CFG,		0x007880),
11962306a36Sopenharmony_ci	REG(ANA_PORT_SFID_CFG,			0x007884),
12062306a36Sopenharmony_ci	REG(ANA_PFC_PFC_CFG,			0x008800),
12162306a36Sopenharmony_ci	REG_RESERVED(ANA_PFC_PFC_TIMER),
12262306a36Sopenharmony_ci	REG_RESERVED(ANA_IPT_OAM_MEP_CFG),
12362306a36Sopenharmony_ci	REG_RESERVED(ANA_IPT_IPT),
12462306a36Sopenharmony_ci	REG_RESERVED(ANA_PPT_PPT),
12562306a36Sopenharmony_ci	REG_RESERVED(ANA_FID_MAP_FID_MAP),
12662306a36Sopenharmony_ci	REG(ANA_AGGR_CFG,			0x008a68),
12762306a36Sopenharmony_ci	REG(ANA_CPUQ_CFG,			0x008a6c),
12862306a36Sopenharmony_ci	REG_RESERVED(ANA_CPUQ_CFG2),
12962306a36Sopenharmony_ci	REG(ANA_CPUQ_8021_CFG,			0x008a74),
13062306a36Sopenharmony_ci	REG(ANA_DSCP_CFG,			0x008ab4),
13162306a36Sopenharmony_ci	REG(ANA_DSCP_REWR_CFG,			0x008bb4),
13262306a36Sopenharmony_ci	REG(ANA_VCAP_RNG_TYPE_CFG,		0x008bf4),
13362306a36Sopenharmony_ci	REG(ANA_VCAP_RNG_VAL_CFG,		0x008c14),
13462306a36Sopenharmony_ci	REG_RESERVED(ANA_VRAP_CFG),
13562306a36Sopenharmony_ci	REG_RESERVED(ANA_VRAP_HDR_DATA),
13662306a36Sopenharmony_ci	REG_RESERVED(ANA_VRAP_HDR_MASK),
13762306a36Sopenharmony_ci	REG(ANA_DISCARD_CFG,			0x008c40),
13862306a36Sopenharmony_ci	REG(ANA_FID_CFG,			0x008c44),
13962306a36Sopenharmony_ci	REG(ANA_POL_PIR_CFG,			0x004000),
14062306a36Sopenharmony_ci	REG(ANA_POL_CIR_CFG,			0x004004),
14162306a36Sopenharmony_ci	REG(ANA_POL_MODE_CFG,			0x004008),
14262306a36Sopenharmony_ci	REG(ANA_POL_PIR_STATE,			0x00400c),
14362306a36Sopenharmony_ci	REG(ANA_POL_CIR_STATE,			0x004010),
14462306a36Sopenharmony_ci	REG_RESERVED(ANA_POL_STATE),
14562306a36Sopenharmony_ci	REG(ANA_POL_FLOWC,			0x008c48),
14662306a36Sopenharmony_ci	REG(ANA_POL_HYST,			0x008cb4),
14762306a36Sopenharmony_ci	REG_RESERVED(ANA_POL_MISC_CFG),
14862306a36Sopenharmony_ci};
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic const u32 vsc9959_qs_regmap[] = {
15162306a36Sopenharmony_ci	REG(QS_XTR_GRP_CFG,			0x000000),
15262306a36Sopenharmony_ci	REG(QS_XTR_RD,				0x000008),
15362306a36Sopenharmony_ci	REG(QS_XTR_FRM_PRUNING,			0x000010),
15462306a36Sopenharmony_ci	REG(QS_XTR_FLUSH,			0x000018),
15562306a36Sopenharmony_ci	REG(QS_XTR_DATA_PRESENT,		0x00001c),
15662306a36Sopenharmony_ci	REG(QS_XTR_CFG,				0x000020),
15762306a36Sopenharmony_ci	REG(QS_INJ_GRP_CFG,			0x000024),
15862306a36Sopenharmony_ci	REG(QS_INJ_WR,				0x00002c),
15962306a36Sopenharmony_ci	REG(QS_INJ_CTRL,			0x000034),
16062306a36Sopenharmony_ci	REG(QS_INJ_STATUS,			0x00003c),
16162306a36Sopenharmony_ci	REG(QS_INJ_ERR,				0x000040),
16262306a36Sopenharmony_ci	REG_RESERVED(QS_INH_DBG),
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic const u32 vsc9959_vcap_regmap[] = {
16662306a36Sopenharmony_ci	/* VCAP_CORE_CFG */
16762306a36Sopenharmony_ci	REG(VCAP_CORE_UPDATE_CTRL,		0x000000),
16862306a36Sopenharmony_ci	REG(VCAP_CORE_MV_CFG,			0x000004),
16962306a36Sopenharmony_ci	/* VCAP_CORE_CACHE */
17062306a36Sopenharmony_ci	REG(VCAP_CACHE_ENTRY_DAT,		0x000008),
17162306a36Sopenharmony_ci	REG(VCAP_CACHE_MASK_DAT,		0x000108),
17262306a36Sopenharmony_ci	REG(VCAP_CACHE_ACTION_DAT,		0x000208),
17362306a36Sopenharmony_ci	REG(VCAP_CACHE_CNT_DAT,			0x000308),
17462306a36Sopenharmony_ci	REG(VCAP_CACHE_TG_DAT,			0x000388),
17562306a36Sopenharmony_ci	/* VCAP_CONST */
17662306a36Sopenharmony_ci	REG(VCAP_CONST_VCAP_VER,		0x000398),
17762306a36Sopenharmony_ci	REG(VCAP_CONST_ENTRY_WIDTH,		0x00039c),
17862306a36Sopenharmony_ci	REG(VCAP_CONST_ENTRY_CNT,		0x0003a0),
17962306a36Sopenharmony_ci	REG(VCAP_CONST_ENTRY_SWCNT,		0x0003a4),
18062306a36Sopenharmony_ci	REG(VCAP_CONST_ENTRY_TG_WIDTH,		0x0003a8),
18162306a36Sopenharmony_ci	REG(VCAP_CONST_ACTION_DEF_CNT,		0x0003ac),
18262306a36Sopenharmony_ci	REG(VCAP_CONST_ACTION_WIDTH,		0x0003b0),
18362306a36Sopenharmony_ci	REG(VCAP_CONST_CNT_WIDTH,		0x0003b4),
18462306a36Sopenharmony_ci	REG(VCAP_CONST_CORE_CNT,		0x0003b8),
18562306a36Sopenharmony_ci	REG(VCAP_CONST_IF_CNT,			0x0003bc),
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic const u32 vsc9959_qsys_regmap[] = {
18962306a36Sopenharmony_ci	REG(QSYS_PORT_MODE,			0x00f460),
19062306a36Sopenharmony_ci	REG(QSYS_SWITCH_PORT_MODE,		0x00f480),
19162306a36Sopenharmony_ci	REG(QSYS_STAT_CNT_CFG,			0x00f49c),
19262306a36Sopenharmony_ci	REG(QSYS_EEE_CFG,			0x00f4a0),
19362306a36Sopenharmony_ci	REG(QSYS_EEE_THRES,			0x00f4b8),
19462306a36Sopenharmony_ci	REG(QSYS_IGR_NO_SHARING,		0x00f4bc),
19562306a36Sopenharmony_ci	REG(QSYS_EGR_NO_SHARING,		0x00f4c0),
19662306a36Sopenharmony_ci	REG(QSYS_SW_STATUS,			0x00f4c4),
19762306a36Sopenharmony_ci	REG(QSYS_EXT_CPU_CFG,			0x00f4e0),
19862306a36Sopenharmony_ci	REG_RESERVED(QSYS_PAD_CFG),
19962306a36Sopenharmony_ci	REG(QSYS_CPU_GROUP_MAP,			0x00f4e8),
20062306a36Sopenharmony_ci	REG_RESERVED(QSYS_QMAP),
20162306a36Sopenharmony_ci	REG_RESERVED(QSYS_ISDX_SGRP),
20262306a36Sopenharmony_ci	REG_RESERVED(QSYS_TIMED_FRAME_ENTRY),
20362306a36Sopenharmony_ci	REG(QSYS_TFRM_MISC,			0x00f50c),
20462306a36Sopenharmony_ci	REG(QSYS_TFRM_PORT_DLY,			0x00f510),
20562306a36Sopenharmony_ci	REG(QSYS_TFRM_TIMER_CFG_1,		0x00f514),
20662306a36Sopenharmony_ci	REG(QSYS_TFRM_TIMER_CFG_2,		0x00f518),
20762306a36Sopenharmony_ci	REG(QSYS_TFRM_TIMER_CFG_3,		0x00f51c),
20862306a36Sopenharmony_ci	REG(QSYS_TFRM_TIMER_CFG_4,		0x00f520),
20962306a36Sopenharmony_ci	REG(QSYS_TFRM_TIMER_CFG_5,		0x00f524),
21062306a36Sopenharmony_ci	REG(QSYS_TFRM_TIMER_CFG_6,		0x00f528),
21162306a36Sopenharmony_ci	REG(QSYS_TFRM_TIMER_CFG_7,		0x00f52c),
21262306a36Sopenharmony_ci	REG(QSYS_TFRM_TIMER_CFG_8,		0x00f530),
21362306a36Sopenharmony_ci	REG(QSYS_RED_PROFILE,			0x00f534),
21462306a36Sopenharmony_ci	REG(QSYS_RES_QOS_MODE,			0x00f574),
21562306a36Sopenharmony_ci	REG(QSYS_RES_CFG,			0x00c000),
21662306a36Sopenharmony_ci	REG(QSYS_RES_STAT,			0x00c004),
21762306a36Sopenharmony_ci	REG(QSYS_EGR_DROP_MODE,			0x00f578),
21862306a36Sopenharmony_ci	REG(QSYS_EQ_CTRL,			0x00f57c),
21962306a36Sopenharmony_ci	REG_RESERVED(QSYS_EVENTS_CORE),
22062306a36Sopenharmony_ci	REG(QSYS_QMAXSDU_CFG_0,			0x00f584),
22162306a36Sopenharmony_ci	REG(QSYS_QMAXSDU_CFG_1,			0x00f5a0),
22262306a36Sopenharmony_ci	REG(QSYS_QMAXSDU_CFG_2,			0x00f5bc),
22362306a36Sopenharmony_ci	REG(QSYS_QMAXSDU_CFG_3,			0x00f5d8),
22462306a36Sopenharmony_ci	REG(QSYS_QMAXSDU_CFG_4,			0x00f5f4),
22562306a36Sopenharmony_ci	REG(QSYS_QMAXSDU_CFG_5,			0x00f610),
22662306a36Sopenharmony_ci	REG(QSYS_QMAXSDU_CFG_6,			0x00f62c),
22762306a36Sopenharmony_ci	REG(QSYS_QMAXSDU_CFG_7,			0x00f648),
22862306a36Sopenharmony_ci	REG(QSYS_PREEMPTION_CFG,		0x00f664),
22962306a36Sopenharmony_ci	REG(QSYS_CIR_CFG,			0x000000),
23062306a36Sopenharmony_ci	REG(QSYS_EIR_CFG,			0x000004),
23162306a36Sopenharmony_ci	REG(QSYS_SE_CFG,			0x000008),
23262306a36Sopenharmony_ci	REG(QSYS_SE_DWRR_CFG,			0x00000c),
23362306a36Sopenharmony_ci	REG_RESERVED(QSYS_SE_CONNECT),
23462306a36Sopenharmony_ci	REG(QSYS_SE_DLB_SENSE,			0x000040),
23562306a36Sopenharmony_ci	REG(QSYS_CIR_STATE,			0x000044),
23662306a36Sopenharmony_ci	REG(QSYS_EIR_STATE,			0x000048),
23762306a36Sopenharmony_ci	REG_RESERVED(QSYS_SE_STATE),
23862306a36Sopenharmony_ci	REG(QSYS_HSCH_MISC_CFG,			0x00f67c),
23962306a36Sopenharmony_ci	REG(QSYS_TAG_CONFIG,			0x00f680),
24062306a36Sopenharmony_ci	REG(QSYS_TAS_PARAM_CFG_CTRL,		0x00f698),
24162306a36Sopenharmony_ci	REG(QSYS_PORT_MAX_SDU,			0x00f69c),
24262306a36Sopenharmony_ci	REG(QSYS_PARAM_CFG_REG_1,		0x00f440),
24362306a36Sopenharmony_ci	REG(QSYS_PARAM_CFG_REG_2,		0x00f444),
24462306a36Sopenharmony_ci	REG(QSYS_PARAM_CFG_REG_3,		0x00f448),
24562306a36Sopenharmony_ci	REG(QSYS_PARAM_CFG_REG_4,		0x00f44c),
24662306a36Sopenharmony_ci	REG(QSYS_PARAM_CFG_REG_5,		0x00f450),
24762306a36Sopenharmony_ci	REG(QSYS_GCL_CFG_REG_1,			0x00f454),
24862306a36Sopenharmony_ci	REG(QSYS_GCL_CFG_REG_2,			0x00f458),
24962306a36Sopenharmony_ci	REG(QSYS_PARAM_STATUS_REG_1,		0x00f400),
25062306a36Sopenharmony_ci	REG(QSYS_PARAM_STATUS_REG_2,		0x00f404),
25162306a36Sopenharmony_ci	REG(QSYS_PARAM_STATUS_REG_3,		0x00f408),
25262306a36Sopenharmony_ci	REG(QSYS_PARAM_STATUS_REG_4,		0x00f40c),
25362306a36Sopenharmony_ci	REG(QSYS_PARAM_STATUS_REG_5,		0x00f410),
25462306a36Sopenharmony_ci	REG(QSYS_PARAM_STATUS_REG_6,		0x00f414),
25562306a36Sopenharmony_ci	REG(QSYS_PARAM_STATUS_REG_7,		0x00f418),
25662306a36Sopenharmony_ci	REG(QSYS_PARAM_STATUS_REG_8,		0x00f41c),
25762306a36Sopenharmony_ci	REG(QSYS_PARAM_STATUS_REG_9,		0x00f420),
25862306a36Sopenharmony_ci	REG(QSYS_GCL_STATUS_REG_1,		0x00f424),
25962306a36Sopenharmony_ci	REG(QSYS_GCL_STATUS_REG_2,		0x00f428),
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic const u32 vsc9959_rew_regmap[] = {
26362306a36Sopenharmony_ci	REG(REW_PORT_VLAN_CFG,			0x000000),
26462306a36Sopenharmony_ci	REG(REW_TAG_CFG,			0x000004),
26562306a36Sopenharmony_ci	REG(REW_PORT_CFG,			0x000008),
26662306a36Sopenharmony_ci	REG(REW_DSCP_CFG,			0x00000c),
26762306a36Sopenharmony_ci	REG(REW_PCP_DEI_QOS_MAP_CFG,		0x000010),
26862306a36Sopenharmony_ci	REG(REW_PTP_CFG,			0x000050),
26962306a36Sopenharmony_ci	REG(REW_PTP_DLY1_CFG,			0x000054),
27062306a36Sopenharmony_ci	REG(REW_RED_TAG_CFG,			0x000058),
27162306a36Sopenharmony_ci	REG(REW_DSCP_REMAP_DP1_CFG,		0x000410),
27262306a36Sopenharmony_ci	REG(REW_DSCP_REMAP_CFG,			0x000510),
27362306a36Sopenharmony_ci	REG_RESERVED(REW_STAT_CFG),
27462306a36Sopenharmony_ci	REG_RESERVED(REW_REW_STICKY),
27562306a36Sopenharmony_ci	REG_RESERVED(REW_PPT),
27662306a36Sopenharmony_ci};
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic const u32 vsc9959_sys_regmap[] = {
27962306a36Sopenharmony_ci	REG(SYS_COUNT_RX_OCTETS,		0x000000),
28062306a36Sopenharmony_ci	REG(SYS_COUNT_RX_UNICAST,		0x000004),
28162306a36Sopenharmony_ci	REG(SYS_COUNT_RX_MULTICAST,		0x000008),
28262306a36Sopenharmony_ci	REG(SYS_COUNT_RX_BROADCAST,		0x00000c),
28362306a36Sopenharmony_ci	REG(SYS_COUNT_RX_SHORTS,		0x000010),
28462306a36Sopenharmony_ci	REG(SYS_COUNT_RX_FRAGMENTS,		0x000014),
28562306a36Sopenharmony_ci	REG(SYS_COUNT_RX_JABBERS,		0x000018),
28662306a36Sopenharmony_ci	REG(SYS_COUNT_RX_CRC_ALIGN_ERRS,	0x00001c),
28762306a36Sopenharmony_ci	REG(SYS_COUNT_RX_SYM_ERRS,		0x000020),
28862306a36Sopenharmony_ci	REG(SYS_COUNT_RX_64,			0x000024),
28962306a36Sopenharmony_ci	REG(SYS_COUNT_RX_65_127,		0x000028),
29062306a36Sopenharmony_ci	REG(SYS_COUNT_RX_128_255,		0x00002c),
29162306a36Sopenharmony_ci	REG(SYS_COUNT_RX_256_511,		0x000030),
29262306a36Sopenharmony_ci	REG(SYS_COUNT_RX_512_1023,		0x000034),
29362306a36Sopenharmony_ci	REG(SYS_COUNT_RX_1024_1526,		0x000038),
29462306a36Sopenharmony_ci	REG(SYS_COUNT_RX_1527_MAX,		0x00003c),
29562306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PAUSE,			0x000040),
29662306a36Sopenharmony_ci	REG(SYS_COUNT_RX_CONTROL,		0x000044),
29762306a36Sopenharmony_ci	REG(SYS_COUNT_RX_LONGS,			0x000048),
29862306a36Sopenharmony_ci	REG(SYS_COUNT_RX_CLASSIFIED_DROPS,	0x00004c),
29962306a36Sopenharmony_ci	REG(SYS_COUNT_RX_RED_PRIO_0,		0x000050),
30062306a36Sopenharmony_ci	REG(SYS_COUNT_RX_RED_PRIO_1,		0x000054),
30162306a36Sopenharmony_ci	REG(SYS_COUNT_RX_RED_PRIO_2,		0x000058),
30262306a36Sopenharmony_ci	REG(SYS_COUNT_RX_RED_PRIO_3,		0x00005c),
30362306a36Sopenharmony_ci	REG(SYS_COUNT_RX_RED_PRIO_4,		0x000060),
30462306a36Sopenharmony_ci	REG(SYS_COUNT_RX_RED_PRIO_5,		0x000064),
30562306a36Sopenharmony_ci	REG(SYS_COUNT_RX_RED_PRIO_6,		0x000068),
30662306a36Sopenharmony_ci	REG(SYS_COUNT_RX_RED_PRIO_7,		0x00006c),
30762306a36Sopenharmony_ci	REG(SYS_COUNT_RX_YELLOW_PRIO_0,		0x000070),
30862306a36Sopenharmony_ci	REG(SYS_COUNT_RX_YELLOW_PRIO_1,		0x000074),
30962306a36Sopenharmony_ci	REG(SYS_COUNT_RX_YELLOW_PRIO_2,		0x000078),
31062306a36Sopenharmony_ci	REG(SYS_COUNT_RX_YELLOW_PRIO_3,		0x00007c),
31162306a36Sopenharmony_ci	REG(SYS_COUNT_RX_YELLOW_PRIO_4,		0x000080),
31262306a36Sopenharmony_ci	REG(SYS_COUNT_RX_YELLOW_PRIO_5,		0x000084),
31362306a36Sopenharmony_ci	REG(SYS_COUNT_RX_YELLOW_PRIO_6,		0x000088),
31462306a36Sopenharmony_ci	REG(SYS_COUNT_RX_YELLOW_PRIO_7,		0x00008c),
31562306a36Sopenharmony_ci	REG(SYS_COUNT_RX_GREEN_PRIO_0,		0x000090),
31662306a36Sopenharmony_ci	REG(SYS_COUNT_RX_GREEN_PRIO_1,		0x000094),
31762306a36Sopenharmony_ci	REG(SYS_COUNT_RX_GREEN_PRIO_2,		0x000098),
31862306a36Sopenharmony_ci	REG(SYS_COUNT_RX_GREEN_PRIO_3,		0x00009c),
31962306a36Sopenharmony_ci	REG(SYS_COUNT_RX_GREEN_PRIO_4,		0x0000a0),
32062306a36Sopenharmony_ci	REG(SYS_COUNT_RX_GREEN_PRIO_5,		0x0000a4),
32162306a36Sopenharmony_ci	REG(SYS_COUNT_RX_GREEN_PRIO_6,		0x0000a8),
32262306a36Sopenharmony_ci	REG(SYS_COUNT_RX_GREEN_PRIO_7,		0x0000ac),
32362306a36Sopenharmony_ci	REG(SYS_COUNT_RX_ASSEMBLY_ERRS,		0x0000b0),
32462306a36Sopenharmony_ci	REG(SYS_COUNT_RX_SMD_ERRS,		0x0000b4),
32562306a36Sopenharmony_ci	REG(SYS_COUNT_RX_ASSEMBLY_OK,		0x0000b8),
32662306a36Sopenharmony_ci	REG(SYS_COUNT_RX_MERGE_FRAGMENTS,	0x0000bc),
32762306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_OCTETS,		0x0000c0),
32862306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_UNICAST,		0x0000c4),
32962306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_MULTICAST,	0x0000c8),
33062306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_BROADCAST,	0x0000cc),
33162306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_SHORTS,		0x0000d0),
33262306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_FRAGMENTS,	0x0000d4),
33362306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_JABBERS,		0x0000d8),
33462306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_CRC_ALIGN_ERRS,	0x0000dc),
33562306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_SYM_ERRS,		0x0000e0),
33662306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_64,		0x0000e4),
33762306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_65_127,		0x0000e8),
33862306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_128_255,		0x0000ec),
33962306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_256_511,		0x0000f0),
34062306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_512_1023,		0x0000f4),
34162306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_1024_1526,	0x0000f8),
34262306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_1527_MAX,		0x0000fc),
34362306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_PAUSE,		0x000100),
34462306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_CONTROL,		0x000104),
34562306a36Sopenharmony_ci	REG(SYS_COUNT_RX_PMAC_LONGS,		0x000108),
34662306a36Sopenharmony_ci	REG(SYS_COUNT_TX_OCTETS,		0x000200),
34762306a36Sopenharmony_ci	REG(SYS_COUNT_TX_UNICAST,		0x000204),
34862306a36Sopenharmony_ci	REG(SYS_COUNT_TX_MULTICAST,		0x000208),
34962306a36Sopenharmony_ci	REG(SYS_COUNT_TX_BROADCAST,		0x00020c),
35062306a36Sopenharmony_ci	REG(SYS_COUNT_TX_COLLISION,		0x000210),
35162306a36Sopenharmony_ci	REG(SYS_COUNT_TX_DROPS,			0x000214),
35262306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PAUSE,			0x000218),
35362306a36Sopenharmony_ci	REG(SYS_COUNT_TX_64,			0x00021c),
35462306a36Sopenharmony_ci	REG(SYS_COUNT_TX_65_127,		0x000220),
35562306a36Sopenharmony_ci	REG(SYS_COUNT_TX_128_255,		0x000224),
35662306a36Sopenharmony_ci	REG(SYS_COUNT_TX_256_511,		0x000228),
35762306a36Sopenharmony_ci	REG(SYS_COUNT_TX_512_1023,		0x00022c),
35862306a36Sopenharmony_ci	REG(SYS_COUNT_TX_1024_1526,		0x000230),
35962306a36Sopenharmony_ci	REG(SYS_COUNT_TX_1527_MAX,		0x000234),
36062306a36Sopenharmony_ci	REG(SYS_COUNT_TX_YELLOW_PRIO_0,		0x000238),
36162306a36Sopenharmony_ci	REG(SYS_COUNT_TX_YELLOW_PRIO_1,		0x00023c),
36262306a36Sopenharmony_ci	REG(SYS_COUNT_TX_YELLOW_PRIO_2,		0x000240),
36362306a36Sopenharmony_ci	REG(SYS_COUNT_TX_YELLOW_PRIO_3,		0x000244),
36462306a36Sopenharmony_ci	REG(SYS_COUNT_TX_YELLOW_PRIO_4,		0x000248),
36562306a36Sopenharmony_ci	REG(SYS_COUNT_TX_YELLOW_PRIO_5,		0x00024c),
36662306a36Sopenharmony_ci	REG(SYS_COUNT_TX_YELLOW_PRIO_6,		0x000250),
36762306a36Sopenharmony_ci	REG(SYS_COUNT_TX_YELLOW_PRIO_7,		0x000254),
36862306a36Sopenharmony_ci	REG(SYS_COUNT_TX_GREEN_PRIO_0,		0x000258),
36962306a36Sopenharmony_ci	REG(SYS_COUNT_TX_GREEN_PRIO_1,		0x00025c),
37062306a36Sopenharmony_ci	REG(SYS_COUNT_TX_GREEN_PRIO_2,		0x000260),
37162306a36Sopenharmony_ci	REG(SYS_COUNT_TX_GREEN_PRIO_3,		0x000264),
37262306a36Sopenharmony_ci	REG(SYS_COUNT_TX_GREEN_PRIO_4,		0x000268),
37362306a36Sopenharmony_ci	REG(SYS_COUNT_TX_GREEN_PRIO_5,		0x00026c),
37462306a36Sopenharmony_ci	REG(SYS_COUNT_TX_GREEN_PRIO_6,		0x000270),
37562306a36Sopenharmony_ci	REG(SYS_COUNT_TX_GREEN_PRIO_7,		0x000274),
37662306a36Sopenharmony_ci	REG(SYS_COUNT_TX_AGED,			0x000278),
37762306a36Sopenharmony_ci	REG(SYS_COUNT_TX_MM_HOLD,		0x00027c),
37862306a36Sopenharmony_ci	REG(SYS_COUNT_TX_MERGE_FRAGMENTS,	0x000280),
37962306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_OCTETS,		0x000284),
38062306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_UNICAST,		0x000288),
38162306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_MULTICAST,	0x00028c),
38262306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_BROADCAST,	0x000290),
38362306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_PAUSE,		0x000294),
38462306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_64,		0x000298),
38562306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_65_127,		0x00029c),
38662306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_128_255,		0x0002a0),
38762306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_256_511,		0x0002a4),
38862306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_512_1023,		0x0002a8),
38962306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_1024_1526,	0x0002ac),
39062306a36Sopenharmony_ci	REG(SYS_COUNT_TX_PMAC_1527_MAX,		0x0002b0),
39162306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_LOCAL,		0x000400),
39262306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_TAIL,		0x000404),
39362306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_YELLOW_PRIO_0,	0x000408),
39462306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_YELLOW_PRIO_1,	0x00040c),
39562306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_YELLOW_PRIO_2,	0x000410),
39662306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_YELLOW_PRIO_3,	0x000414),
39762306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_YELLOW_PRIO_4,	0x000418),
39862306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_YELLOW_PRIO_5,	0x00041c),
39962306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_YELLOW_PRIO_6,	0x000420),
40062306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_YELLOW_PRIO_7,	0x000424),
40162306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_GREEN_PRIO_0,	0x000428),
40262306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_GREEN_PRIO_1,	0x00042c),
40362306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_GREEN_PRIO_2,	0x000430),
40462306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_GREEN_PRIO_3,	0x000434),
40562306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_GREEN_PRIO_4,	0x000438),
40662306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_GREEN_PRIO_5,	0x00043c),
40762306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_GREEN_PRIO_6,	0x000440),
40862306a36Sopenharmony_ci	REG(SYS_COUNT_DROP_GREEN_PRIO_7,	0x000444),
40962306a36Sopenharmony_ci	REG(SYS_COUNT_SF_MATCHING_FRAMES,	0x000800),
41062306a36Sopenharmony_ci	REG(SYS_COUNT_SF_NOT_PASSING_FRAMES,	0x000804),
41162306a36Sopenharmony_ci	REG(SYS_COUNT_SF_NOT_PASSING_SDU,	0x000808),
41262306a36Sopenharmony_ci	REG(SYS_COUNT_SF_RED_FRAMES,		0x00080c),
41362306a36Sopenharmony_ci	REG(SYS_RESET_CFG,			0x000e00),
41462306a36Sopenharmony_ci	REG(SYS_SR_ETYPE_CFG,			0x000e04),
41562306a36Sopenharmony_ci	REG(SYS_VLAN_ETYPE_CFG,			0x000e08),
41662306a36Sopenharmony_ci	REG(SYS_PORT_MODE,			0x000e0c),
41762306a36Sopenharmony_ci	REG(SYS_FRONT_PORT_MODE,		0x000e2c),
41862306a36Sopenharmony_ci	REG(SYS_FRM_AGING,			0x000e44),
41962306a36Sopenharmony_ci	REG(SYS_STAT_CFG,			0x000e48),
42062306a36Sopenharmony_ci	REG(SYS_SW_STATUS,			0x000e4c),
42162306a36Sopenharmony_ci	REG_RESERVED(SYS_MISC_CFG),
42262306a36Sopenharmony_ci	REG(SYS_REW_MAC_HIGH_CFG,		0x000e6c),
42362306a36Sopenharmony_ci	REG(SYS_REW_MAC_LOW_CFG,		0x000e84),
42462306a36Sopenharmony_ci	REG(SYS_TIMESTAMP_OFFSET,		0x000e9c),
42562306a36Sopenharmony_ci	REG(SYS_PAUSE_CFG,			0x000ea0),
42662306a36Sopenharmony_ci	REG(SYS_PAUSE_TOT_CFG,			0x000ebc),
42762306a36Sopenharmony_ci	REG(SYS_ATOP,				0x000ec0),
42862306a36Sopenharmony_ci	REG(SYS_ATOP_TOT_CFG,			0x000edc),
42962306a36Sopenharmony_ci	REG(SYS_MAC_FC_CFG,			0x000ee0),
43062306a36Sopenharmony_ci	REG(SYS_MMGT,				0x000ef8),
43162306a36Sopenharmony_ci	REG_RESERVED(SYS_MMGT_FAST),
43262306a36Sopenharmony_ci	REG_RESERVED(SYS_EVENTS_DIF),
43362306a36Sopenharmony_ci	REG_RESERVED(SYS_EVENTS_CORE),
43462306a36Sopenharmony_ci	REG(SYS_PTP_STATUS,			0x000f14),
43562306a36Sopenharmony_ci	REG(SYS_PTP_TXSTAMP,			0x000f18),
43662306a36Sopenharmony_ci	REG(SYS_PTP_NXT,			0x000f1c),
43762306a36Sopenharmony_ci	REG(SYS_PTP_CFG,			0x000f20),
43862306a36Sopenharmony_ci	REG(SYS_RAM_INIT,			0x000f24),
43962306a36Sopenharmony_ci	REG_RESERVED(SYS_CM_ADDR),
44062306a36Sopenharmony_ci	REG_RESERVED(SYS_CM_DATA_WR),
44162306a36Sopenharmony_ci	REG_RESERVED(SYS_CM_DATA_RD),
44262306a36Sopenharmony_ci	REG_RESERVED(SYS_CM_OP),
44362306a36Sopenharmony_ci	REG_RESERVED(SYS_CM_DATA),
44462306a36Sopenharmony_ci};
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic const u32 vsc9959_ptp_regmap[] = {
44762306a36Sopenharmony_ci	REG(PTP_PIN_CFG,			0x000000),
44862306a36Sopenharmony_ci	REG(PTP_PIN_TOD_SEC_MSB,		0x000004),
44962306a36Sopenharmony_ci	REG(PTP_PIN_TOD_SEC_LSB,		0x000008),
45062306a36Sopenharmony_ci	REG(PTP_PIN_TOD_NSEC,			0x00000c),
45162306a36Sopenharmony_ci	REG(PTP_PIN_WF_HIGH_PERIOD,		0x000014),
45262306a36Sopenharmony_ci	REG(PTP_PIN_WF_LOW_PERIOD,		0x000018),
45362306a36Sopenharmony_ci	REG(PTP_CFG_MISC,			0x0000a0),
45462306a36Sopenharmony_ci	REG(PTP_CLK_CFG_ADJ_CFG,		0x0000a4),
45562306a36Sopenharmony_ci	REG(PTP_CLK_CFG_ADJ_FREQ,		0x0000a8),
45662306a36Sopenharmony_ci};
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic const u32 vsc9959_gcb_regmap[] = {
45962306a36Sopenharmony_ci	REG(GCB_SOFT_RST,			0x000004),
46062306a36Sopenharmony_ci};
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic const u32 vsc9959_dev_gmii_regmap[] = {
46362306a36Sopenharmony_ci	REG(DEV_CLOCK_CFG,			0x0),
46462306a36Sopenharmony_ci	REG(DEV_PORT_MISC,			0x4),
46562306a36Sopenharmony_ci	REG(DEV_EVENTS,				0x8),
46662306a36Sopenharmony_ci	REG(DEV_EEE_CFG,			0xc),
46762306a36Sopenharmony_ci	REG(DEV_RX_PATH_DELAY,			0x10),
46862306a36Sopenharmony_ci	REG(DEV_TX_PATH_DELAY,			0x14),
46962306a36Sopenharmony_ci	REG(DEV_PTP_PREDICT_CFG,		0x18),
47062306a36Sopenharmony_ci	REG(DEV_MAC_ENA_CFG,			0x1c),
47162306a36Sopenharmony_ci	REG(DEV_MAC_MODE_CFG,			0x20),
47262306a36Sopenharmony_ci	REG(DEV_MAC_MAXLEN_CFG,			0x24),
47362306a36Sopenharmony_ci	REG(DEV_MAC_TAGS_CFG,			0x28),
47462306a36Sopenharmony_ci	REG(DEV_MAC_ADV_CHK_CFG,		0x2c),
47562306a36Sopenharmony_ci	REG(DEV_MAC_IFG_CFG,			0x30),
47662306a36Sopenharmony_ci	REG(DEV_MAC_HDX_CFG,			0x34),
47762306a36Sopenharmony_ci	REG(DEV_MAC_DBG_CFG,			0x38),
47862306a36Sopenharmony_ci	REG(DEV_MAC_FC_MAC_LOW_CFG,		0x3c),
47962306a36Sopenharmony_ci	REG(DEV_MAC_FC_MAC_HIGH_CFG,		0x40),
48062306a36Sopenharmony_ci	REG(DEV_MAC_STICKY,			0x44),
48162306a36Sopenharmony_ci	REG(DEV_MM_ENABLE_CONFIG,		0x48),
48262306a36Sopenharmony_ci	REG(DEV_MM_VERIF_CONFIG,		0x4C),
48362306a36Sopenharmony_ci	REG(DEV_MM_STATUS,			0x50),
48462306a36Sopenharmony_ci	REG_RESERVED(PCS1G_CFG),
48562306a36Sopenharmony_ci	REG_RESERVED(PCS1G_MODE_CFG),
48662306a36Sopenharmony_ci	REG_RESERVED(PCS1G_SD_CFG),
48762306a36Sopenharmony_ci	REG_RESERVED(PCS1G_ANEG_CFG),
48862306a36Sopenharmony_ci	REG_RESERVED(PCS1G_ANEG_NP_CFG),
48962306a36Sopenharmony_ci	REG_RESERVED(PCS1G_LB_CFG),
49062306a36Sopenharmony_ci	REG_RESERVED(PCS1G_DBG_CFG),
49162306a36Sopenharmony_ci	REG_RESERVED(PCS1G_CDET_CFG),
49262306a36Sopenharmony_ci	REG_RESERVED(PCS1G_ANEG_STATUS),
49362306a36Sopenharmony_ci	REG_RESERVED(PCS1G_ANEG_NP_STATUS),
49462306a36Sopenharmony_ci	REG_RESERVED(PCS1G_LINK_STATUS),
49562306a36Sopenharmony_ci	REG_RESERVED(PCS1G_LINK_DOWN_CNT),
49662306a36Sopenharmony_ci	REG_RESERVED(PCS1G_STICKY),
49762306a36Sopenharmony_ci	REG_RESERVED(PCS1G_DEBUG_STATUS),
49862306a36Sopenharmony_ci	REG_RESERVED(PCS1G_LPI_CFG),
49962306a36Sopenharmony_ci	REG_RESERVED(PCS1G_LPI_WAKE_ERROR_CNT),
50062306a36Sopenharmony_ci	REG_RESERVED(PCS1G_LPI_STATUS),
50162306a36Sopenharmony_ci	REG_RESERVED(PCS1G_TSTPAT_MODE_CFG),
50262306a36Sopenharmony_ci	REG_RESERVED(PCS1G_TSTPAT_STATUS),
50362306a36Sopenharmony_ci	REG_RESERVED(DEV_PCS_FX100_CFG),
50462306a36Sopenharmony_ci	REG_RESERVED(DEV_PCS_FX100_STATUS),
50562306a36Sopenharmony_ci};
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic const u32 *vsc9959_regmap[TARGET_MAX] = {
50862306a36Sopenharmony_ci	[ANA]	= vsc9959_ana_regmap,
50962306a36Sopenharmony_ci	[QS]	= vsc9959_qs_regmap,
51062306a36Sopenharmony_ci	[QSYS]	= vsc9959_qsys_regmap,
51162306a36Sopenharmony_ci	[REW]	= vsc9959_rew_regmap,
51262306a36Sopenharmony_ci	[SYS]	= vsc9959_sys_regmap,
51362306a36Sopenharmony_ci	[S0]	= vsc9959_vcap_regmap,
51462306a36Sopenharmony_ci	[S1]	= vsc9959_vcap_regmap,
51562306a36Sopenharmony_ci	[S2]	= vsc9959_vcap_regmap,
51662306a36Sopenharmony_ci	[PTP]	= vsc9959_ptp_regmap,
51762306a36Sopenharmony_ci	[GCB]	= vsc9959_gcb_regmap,
51862306a36Sopenharmony_ci	[DEV_GMII] = vsc9959_dev_gmii_regmap,
51962306a36Sopenharmony_ci};
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci/* Addresses are relative to the PCI device's base address */
52262306a36Sopenharmony_cistatic const struct resource vsc9959_resources[] = {
52362306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0010000, 0x0010000, "sys"),
52462306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0030000, 0x0010000, "rew"),
52562306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0040000, 0x0000400, "s0"),
52662306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0050000, 0x0000400, "s1"),
52762306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0060000, 0x0000400, "s2"),
52862306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0070000, 0x0000200, "devcpu_gcb"),
52962306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0080000, 0x0000100, "qs"),
53062306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0090000, 0x00000cc, "ptp"),
53162306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0100000, 0x0010000, "port0"),
53262306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0110000, 0x0010000, "port1"),
53362306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0120000, 0x0010000, "port2"),
53462306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0130000, 0x0010000, "port3"),
53562306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0140000, 0x0010000, "port4"),
53662306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0150000, 0x0010000, "port5"),
53762306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0200000, 0x0020000, "qsys"),
53862306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x0280000, 0x0010000, "ana"),
53962306a36Sopenharmony_ci};
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic const char * const vsc9959_resource_names[TARGET_MAX] = {
54262306a36Sopenharmony_ci	[SYS] = "sys",
54362306a36Sopenharmony_ci	[REW] = "rew",
54462306a36Sopenharmony_ci	[S0] = "s0",
54562306a36Sopenharmony_ci	[S1] = "s1",
54662306a36Sopenharmony_ci	[S2] = "s2",
54762306a36Sopenharmony_ci	[GCB] = "devcpu_gcb",
54862306a36Sopenharmony_ci	[QS] = "qs",
54962306a36Sopenharmony_ci	[PTP] = "ptp",
55062306a36Sopenharmony_ci	[QSYS] = "qsys",
55162306a36Sopenharmony_ci	[ANA] = "ana",
55262306a36Sopenharmony_ci};
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/* Port MAC 0 Internal MDIO bus through which the SerDes acting as an
55562306a36Sopenharmony_ci * SGMII/QSGMII MAC PCS can be found.
55662306a36Sopenharmony_ci */
55762306a36Sopenharmony_cistatic const struct resource vsc9959_imdio_res =
55862306a36Sopenharmony_ci	DEFINE_RES_MEM_NAMED(0x8030, 0x10, "imdio");
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic const struct reg_field vsc9959_regfields[REGFIELD_MAX] = {
56162306a36Sopenharmony_ci	[ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6),
56262306a36Sopenharmony_ci	[ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5),
56362306a36Sopenharmony_ci	[ANA_ANEVENTS_FLOOD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 30, 30),
56462306a36Sopenharmony_ci	[ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 26, 26),
56562306a36Sopenharmony_ci	[ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 24, 24),
56662306a36Sopenharmony_ci	[ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 23, 23),
56762306a36Sopenharmony_ci	[ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 22, 22),
56862306a36Sopenharmony_ci	[ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 21, 21),
56962306a36Sopenharmony_ci	[ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 20, 20),
57062306a36Sopenharmony_ci	[ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 19, 19),
57162306a36Sopenharmony_ci	[ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 18, 18),
57262306a36Sopenharmony_ci	[ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 17, 17),
57362306a36Sopenharmony_ci	[ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 15, 15),
57462306a36Sopenharmony_ci	[ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 14, 14),
57562306a36Sopenharmony_ci	[ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 13, 13),
57662306a36Sopenharmony_ci	[ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 12, 12),
57762306a36Sopenharmony_ci	[ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 11, 11),
57862306a36Sopenharmony_ci	[ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 10, 10),
57962306a36Sopenharmony_ci	[ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 9, 9),
58062306a36Sopenharmony_ci	[ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 8, 8),
58162306a36Sopenharmony_ci	[ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 7, 7),
58262306a36Sopenharmony_ci	[ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6),
58362306a36Sopenharmony_ci	[ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5),
58462306a36Sopenharmony_ci	[ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 4, 4),
58562306a36Sopenharmony_ci	[ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 3, 3),
58662306a36Sopenharmony_ci	[ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 2, 2),
58762306a36Sopenharmony_ci	[ANA_ANEVENTS_SEQ_GEN_ERR_0] = REG_FIELD(ANA_ANEVENTS, 1, 1),
58862306a36Sopenharmony_ci	[ANA_ANEVENTS_SEQ_GEN_ERR_1] = REG_FIELD(ANA_ANEVENTS, 0, 0),
58962306a36Sopenharmony_ci	[ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 16, 16),
59062306a36Sopenharmony_ci	[ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 11, 12),
59162306a36Sopenharmony_ci	[ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 10),
59262306a36Sopenharmony_ci	[SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 0, 0),
59362306a36Sopenharmony_ci	[GCB_SOFT_RST_SWC_RST] = REG_FIELD(GCB_SOFT_RST, 0, 0),
59462306a36Sopenharmony_ci	/* Replicated per number of ports (7), register size 4 per port */
59562306a36Sopenharmony_ci	[QSYS_SWITCH_PORT_MODE_PORT_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 14, 14, 7, 4),
59662306a36Sopenharmony_ci	[QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 11, 13, 7, 4),
59762306a36Sopenharmony_ci	[QSYS_SWITCH_PORT_MODE_YEL_RSRVD] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 10, 10, 7, 4),
59862306a36Sopenharmony_ci	[QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 9, 9, 7, 4),
59962306a36Sopenharmony_ci	[QSYS_SWITCH_PORT_MODE_TX_PFC_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 1, 8, 7, 4),
60062306a36Sopenharmony_ci	[QSYS_SWITCH_PORT_MODE_TX_PFC_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 0, 0, 7, 4),
60162306a36Sopenharmony_ci	[SYS_PORT_MODE_DATA_WO_TS] = REG_FIELD_ID(SYS_PORT_MODE, 5, 6, 7, 4),
60262306a36Sopenharmony_ci	[SYS_PORT_MODE_INCL_INJ_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 3, 4, 7, 4),
60362306a36Sopenharmony_ci	[SYS_PORT_MODE_INCL_XTR_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 1, 2, 7, 4),
60462306a36Sopenharmony_ci	[SYS_PORT_MODE_INCL_HDR_ERR] = REG_FIELD_ID(SYS_PORT_MODE, 0, 0, 7, 4),
60562306a36Sopenharmony_ci	[SYS_PAUSE_CFG_PAUSE_START] = REG_FIELD_ID(SYS_PAUSE_CFG, 10, 18, 7, 4),
60662306a36Sopenharmony_ci	[SYS_PAUSE_CFG_PAUSE_STOP] = REG_FIELD_ID(SYS_PAUSE_CFG, 1, 9, 7, 4),
60762306a36Sopenharmony_ci	[SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 7, 4),
60862306a36Sopenharmony_ci};
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic const struct vcap_field vsc9959_vcap_es0_keys[] = {
61162306a36Sopenharmony_ci	[VCAP_ES0_EGR_PORT]			= {  0,  3},
61262306a36Sopenharmony_ci	[VCAP_ES0_IGR_PORT]			= {  3,  3},
61362306a36Sopenharmony_ci	[VCAP_ES0_RSV]				= {  6,  2},
61462306a36Sopenharmony_ci	[VCAP_ES0_L2_MC]			= {  8,  1},
61562306a36Sopenharmony_ci	[VCAP_ES0_L2_BC]			= {  9,  1},
61662306a36Sopenharmony_ci	[VCAP_ES0_VID]				= { 10, 12},
61762306a36Sopenharmony_ci	[VCAP_ES0_DP]				= { 22,  1},
61862306a36Sopenharmony_ci	[VCAP_ES0_PCP]				= { 23,  3},
61962306a36Sopenharmony_ci};
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic const struct vcap_field vsc9959_vcap_es0_actions[] = {
62262306a36Sopenharmony_ci	[VCAP_ES0_ACT_PUSH_OUTER_TAG]		= {  0,  2},
62362306a36Sopenharmony_ci	[VCAP_ES0_ACT_PUSH_INNER_TAG]		= {  2,  1},
62462306a36Sopenharmony_ci	[VCAP_ES0_ACT_TAG_A_TPID_SEL]		= {  3,  2},
62562306a36Sopenharmony_ci	[VCAP_ES0_ACT_TAG_A_VID_SEL]		= {  5,  1},
62662306a36Sopenharmony_ci	[VCAP_ES0_ACT_TAG_A_PCP_SEL]		= {  6,  2},
62762306a36Sopenharmony_ci	[VCAP_ES0_ACT_TAG_A_DEI_SEL]		= {  8,  2},
62862306a36Sopenharmony_ci	[VCAP_ES0_ACT_TAG_B_TPID_SEL]		= { 10,  2},
62962306a36Sopenharmony_ci	[VCAP_ES0_ACT_TAG_B_VID_SEL]		= { 12,  1},
63062306a36Sopenharmony_ci	[VCAP_ES0_ACT_TAG_B_PCP_SEL]		= { 13,  2},
63162306a36Sopenharmony_ci	[VCAP_ES0_ACT_TAG_B_DEI_SEL]		= { 15,  2},
63262306a36Sopenharmony_ci	[VCAP_ES0_ACT_VID_A_VAL]		= { 17, 12},
63362306a36Sopenharmony_ci	[VCAP_ES0_ACT_PCP_A_VAL]		= { 29,  3},
63462306a36Sopenharmony_ci	[VCAP_ES0_ACT_DEI_A_VAL]		= { 32,  1},
63562306a36Sopenharmony_ci	[VCAP_ES0_ACT_VID_B_VAL]		= { 33, 12},
63662306a36Sopenharmony_ci	[VCAP_ES0_ACT_PCP_B_VAL]		= { 45,  3},
63762306a36Sopenharmony_ci	[VCAP_ES0_ACT_DEI_B_VAL]		= { 48,  1},
63862306a36Sopenharmony_ci	[VCAP_ES0_ACT_RSV]			= { 49, 23},
63962306a36Sopenharmony_ci	[VCAP_ES0_ACT_HIT_STICKY]		= { 72,  1},
64062306a36Sopenharmony_ci};
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic const struct vcap_field vsc9959_vcap_is1_keys[] = {
64362306a36Sopenharmony_ci	[VCAP_IS1_HK_TYPE]			= {  0,   1},
64462306a36Sopenharmony_ci	[VCAP_IS1_HK_LOOKUP]			= {  1,   2},
64562306a36Sopenharmony_ci	[VCAP_IS1_HK_IGR_PORT_MASK]		= {  3,   7},
64662306a36Sopenharmony_ci	[VCAP_IS1_HK_RSV]			= { 10,   9},
64762306a36Sopenharmony_ci	[VCAP_IS1_HK_OAM_Y1731]			= { 19,   1},
64862306a36Sopenharmony_ci	[VCAP_IS1_HK_L2_MC]			= { 20,   1},
64962306a36Sopenharmony_ci	[VCAP_IS1_HK_L2_BC]			= { 21,   1},
65062306a36Sopenharmony_ci	[VCAP_IS1_HK_IP_MC]			= { 22,   1},
65162306a36Sopenharmony_ci	[VCAP_IS1_HK_VLAN_TAGGED]		= { 23,   1},
65262306a36Sopenharmony_ci	[VCAP_IS1_HK_VLAN_DBL_TAGGED]		= { 24,   1},
65362306a36Sopenharmony_ci	[VCAP_IS1_HK_TPID]			= { 25,   1},
65462306a36Sopenharmony_ci	[VCAP_IS1_HK_VID]			= { 26,  12},
65562306a36Sopenharmony_ci	[VCAP_IS1_HK_DEI]			= { 38,   1},
65662306a36Sopenharmony_ci	[VCAP_IS1_HK_PCP]			= { 39,   3},
65762306a36Sopenharmony_ci	/* Specific Fields for IS1 Half Key S1_NORMAL */
65862306a36Sopenharmony_ci	[VCAP_IS1_HK_L2_SMAC]			= { 42,  48},
65962306a36Sopenharmony_ci	[VCAP_IS1_HK_ETYPE_LEN]			= { 90,   1},
66062306a36Sopenharmony_ci	[VCAP_IS1_HK_ETYPE]			= { 91,  16},
66162306a36Sopenharmony_ci	[VCAP_IS1_HK_IP_SNAP]			= {107,   1},
66262306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4]			= {108,   1},
66362306a36Sopenharmony_ci	/* Layer-3 Information */
66462306a36Sopenharmony_ci	[VCAP_IS1_HK_L3_FRAGMENT]		= {109,   1},
66562306a36Sopenharmony_ci	[VCAP_IS1_HK_L3_FRAG_OFS_GT0]		= {110,   1},
66662306a36Sopenharmony_ci	[VCAP_IS1_HK_L3_OPTIONS]		= {111,   1},
66762306a36Sopenharmony_ci	[VCAP_IS1_HK_L3_DSCP]			= {112,   6},
66862306a36Sopenharmony_ci	[VCAP_IS1_HK_L3_IP4_SIP]		= {118,  32},
66962306a36Sopenharmony_ci	/* Layer-4 Information */
67062306a36Sopenharmony_ci	[VCAP_IS1_HK_TCP_UDP]			= {150,   1},
67162306a36Sopenharmony_ci	[VCAP_IS1_HK_TCP]			= {151,   1},
67262306a36Sopenharmony_ci	[VCAP_IS1_HK_L4_SPORT]			= {152,  16},
67362306a36Sopenharmony_ci	[VCAP_IS1_HK_L4_RNG]			= {168,   8},
67462306a36Sopenharmony_ci	/* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */
67562306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_INNER_TPID]            = { 42,   1},
67662306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_INNER_VID]		= { 43,  12},
67762306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_INNER_DEI]		= { 55,   1},
67862306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_INNER_PCP]		= { 56,   3},
67962306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_IP4]			= { 59,   1},
68062306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_L3_FRAGMENT]		= { 60,   1},
68162306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0]	= { 61,   1},
68262306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_L3_OPTIONS]		= { 62,   1},
68362306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_L3_DSCP]		= { 63,   6},
68462306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_L3_IP4_DIP]		= { 69,  32},
68562306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_L3_IP4_SIP]		= {101,  32},
68662306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_L3_PROTO]		= {133,   8},
68762306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_TCP_UDP]		= {141,   1},
68862306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_TCP]			= {142,   1},
68962306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_L4_RNG]		= {143,   8},
69062306a36Sopenharmony_ci	[VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE]	= {151,  32},
69162306a36Sopenharmony_ci};
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic const struct vcap_field vsc9959_vcap_is1_actions[] = {
69462306a36Sopenharmony_ci	[VCAP_IS1_ACT_DSCP_ENA]			= {  0,  1},
69562306a36Sopenharmony_ci	[VCAP_IS1_ACT_DSCP_VAL]			= {  1,  6},
69662306a36Sopenharmony_ci	[VCAP_IS1_ACT_QOS_ENA]			= {  7,  1},
69762306a36Sopenharmony_ci	[VCAP_IS1_ACT_QOS_VAL]			= {  8,  3},
69862306a36Sopenharmony_ci	[VCAP_IS1_ACT_DP_ENA]			= { 11,  1},
69962306a36Sopenharmony_ci	[VCAP_IS1_ACT_DP_VAL]			= { 12,  1},
70062306a36Sopenharmony_ci	[VCAP_IS1_ACT_PAG_OVERRIDE_MASK]	= { 13,  8},
70162306a36Sopenharmony_ci	[VCAP_IS1_ACT_PAG_VAL]			= { 21,  8},
70262306a36Sopenharmony_ci	[VCAP_IS1_ACT_RSV]			= { 29,  9},
70362306a36Sopenharmony_ci	/* The fields below are incorrectly shifted by 2 in the manual */
70462306a36Sopenharmony_ci	[VCAP_IS1_ACT_VID_REPLACE_ENA]		= { 38,  1},
70562306a36Sopenharmony_ci	[VCAP_IS1_ACT_VID_ADD_VAL]		= { 39, 12},
70662306a36Sopenharmony_ci	[VCAP_IS1_ACT_FID_SEL]			= { 51,  2},
70762306a36Sopenharmony_ci	[VCAP_IS1_ACT_FID_VAL]			= { 53, 13},
70862306a36Sopenharmony_ci	[VCAP_IS1_ACT_PCP_DEI_ENA]		= { 66,  1},
70962306a36Sopenharmony_ci	[VCAP_IS1_ACT_PCP_VAL]			= { 67,  3},
71062306a36Sopenharmony_ci	[VCAP_IS1_ACT_DEI_VAL]			= { 70,  1},
71162306a36Sopenharmony_ci	[VCAP_IS1_ACT_VLAN_POP_CNT_ENA]		= { 71,  1},
71262306a36Sopenharmony_ci	[VCAP_IS1_ACT_VLAN_POP_CNT]		= { 72,  2},
71362306a36Sopenharmony_ci	[VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA]	= { 74,  4},
71462306a36Sopenharmony_ci	[VCAP_IS1_ACT_HIT_STICKY]		= { 78,  1},
71562306a36Sopenharmony_ci};
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic struct vcap_field vsc9959_vcap_is2_keys[] = {
71862306a36Sopenharmony_ci	/* Common: 41 bits */
71962306a36Sopenharmony_ci	[VCAP_IS2_TYPE]				= {  0,   4},
72062306a36Sopenharmony_ci	[VCAP_IS2_HK_FIRST]			= {  4,   1},
72162306a36Sopenharmony_ci	[VCAP_IS2_HK_PAG]			= {  5,   8},
72262306a36Sopenharmony_ci	[VCAP_IS2_HK_IGR_PORT_MASK]		= { 13,   7},
72362306a36Sopenharmony_ci	[VCAP_IS2_HK_RSV2]			= { 20,   1},
72462306a36Sopenharmony_ci	[VCAP_IS2_HK_HOST_MATCH]		= { 21,   1},
72562306a36Sopenharmony_ci	[VCAP_IS2_HK_L2_MC]			= { 22,   1},
72662306a36Sopenharmony_ci	[VCAP_IS2_HK_L2_BC]			= { 23,   1},
72762306a36Sopenharmony_ci	[VCAP_IS2_HK_VLAN_TAGGED]		= { 24,   1},
72862306a36Sopenharmony_ci	[VCAP_IS2_HK_VID]			= { 25,  12},
72962306a36Sopenharmony_ci	[VCAP_IS2_HK_DEI]			= { 37,   1},
73062306a36Sopenharmony_ci	[VCAP_IS2_HK_PCP]			= { 38,   3},
73162306a36Sopenharmony_ci	/* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */
73262306a36Sopenharmony_ci	[VCAP_IS2_HK_L2_DMAC]			= { 41,  48},
73362306a36Sopenharmony_ci	[VCAP_IS2_HK_L2_SMAC]			= { 89,  48},
73462306a36Sopenharmony_ci	/* MAC_ETYPE (TYPE=000) */
73562306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ETYPE_ETYPE]		= {137,  16},
73662306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0]	= {153,  16},
73762306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1]	= {169,   8},
73862306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2]	= {177,   3},
73962306a36Sopenharmony_ci	/* MAC_LLC (TYPE=001) */
74062306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_LLC_L2_LLC]		= {137,  40},
74162306a36Sopenharmony_ci	/* MAC_SNAP (TYPE=010) */
74262306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_SNAP_L2_SNAP]		= {137,  40},
74362306a36Sopenharmony_ci	/* MAC_ARP (TYPE=011) */
74462306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_SMAC]		= { 41,  48},
74562306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK]	= { 89,   1},
74662306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK]	= { 90,   1},
74762306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_LEN_OK]		= { 91,   1},
74862306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_TARGET_MATCH]	= { 92,   1},
74962306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_SENDER_MATCH]	= { 93,   1},
75062306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN]	= { 94,   1},
75162306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_OPCODE]		= { 95,   2},
75262306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP]	= { 97,  32},
75362306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP]	= {129,  32},
75462306a36Sopenharmony_ci	[VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP]	= {161,   1},
75562306a36Sopenharmony_ci	/* IP4_TCP_UDP / IP4_OTHER common */
75662306a36Sopenharmony_ci	[VCAP_IS2_HK_IP4]			= { 41,   1},
75762306a36Sopenharmony_ci	[VCAP_IS2_HK_L3_FRAGMENT]		= { 42,   1},
75862306a36Sopenharmony_ci	[VCAP_IS2_HK_L3_FRAG_OFS_GT0]		= { 43,   1},
75962306a36Sopenharmony_ci	[VCAP_IS2_HK_L3_OPTIONS]		= { 44,   1},
76062306a36Sopenharmony_ci	[VCAP_IS2_HK_IP4_L3_TTL_GT0]		= { 45,   1},
76162306a36Sopenharmony_ci	[VCAP_IS2_HK_L3_TOS]			= { 46,   8},
76262306a36Sopenharmony_ci	[VCAP_IS2_HK_L3_IP4_DIP]		= { 54,  32},
76362306a36Sopenharmony_ci	[VCAP_IS2_HK_L3_IP4_SIP]		= { 86,  32},
76462306a36Sopenharmony_ci	[VCAP_IS2_HK_DIP_EQ_SIP]		= {118,   1},
76562306a36Sopenharmony_ci	/* IP4_TCP_UDP (TYPE=100) */
76662306a36Sopenharmony_ci	[VCAP_IS2_HK_TCP]			= {119,   1},
76762306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_DPORT]			= {120,  16},
76862306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_SPORT]			= {136,  16},
76962306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_RNG]			= {152,   8},
77062306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_SPORT_EQ_DPORT]		= {160,   1},
77162306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_SEQUENCE_EQ0]		= {161,   1},
77262306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_FIN]			= {162,   1},
77362306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_SYN]			= {163,   1},
77462306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_RST]			= {164,   1},
77562306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_PSH]			= {165,   1},
77662306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_ACK]			= {166,   1},
77762306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_URG]			= {167,   1},
77862306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_1588_DOM]		= {168,   8},
77962306a36Sopenharmony_ci	[VCAP_IS2_HK_L4_1588_VER]		= {176,   4},
78062306a36Sopenharmony_ci	/* IP4_OTHER (TYPE=101) */
78162306a36Sopenharmony_ci	[VCAP_IS2_HK_IP4_L3_PROTO]		= {119,   8},
78262306a36Sopenharmony_ci	[VCAP_IS2_HK_L3_PAYLOAD]		= {127,  56},
78362306a36Sopenharmony_ci	/* IP6_STD (TYPE=110) */
78462306a36Sopenharmony_ci	[VCAP_IS2_HK_IP6_L3_TTL_GT0]		= { 41,   1},
78562306a36Sopenharmony_ci	[VCAP_IS2_HK_L3_IP6_SIP]		= { 42, 128},
78662306a36Sopenharmony_ci	[VCAP_IS2_HK_IP6_L3_PROTO]		= {170,   8},
78762306a36Sopenharmony_ci	/* OAM (TYPE=111) */
78862306a36Sopenharmony_ci	[VCAP_IS2_HK_OAM_MEL_FLAGS]		= {137,   7},
78962306a36Sopenharmony_ci	[VCAP_IS2_HK_OAM_VER]			= {144,   5},
79062306a36Sopenharmony_ci	[VCAP_IS2_HK_OAM_OPCODE]		= {149,   8},
79162306a36Sopenharmony_ci	[VCAP_IS2_HK_OAM_FLAGS]			= {157,   8},
79262306a36Sopenharmony_ci	[VCAP_IS2_HK_OAM_MEPID]			= {165,  16},
79362306a36Sopenharmony_ci	[VCAP_IS2_HK_OAM_CCM_CNTS_EQ0]		= {181,   1},
79462306a36Sopenharmony_ci	[VCAP_IS2_HK_OAM_IS_Y1731]		= {182,   1},
79562306a36Sopenharmony_ci};
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic struct vcap_field vsc9959_vcap_is2_actions[] = {
79862306a36Sopenharmony_ci	[VCAP_IS2_ACT_HIT_ME_ONCE]		= {  0,  1},
79962306a36Sopenharmony_ci	[VCAP_IS2_ACT_CPU_COPY_ENA]		= {  1,  1},
80062306a36Sopenharmony_ci	[VCAP_IS2_ACT_CPU_QU_NUM]		= {  2,  3},
80162306a36Sopenharmony_ci	[VCAP_IS2_ACT_MASK_MODE]		= {  5,  2},
80262306a36Sopenharmony_ci	[VCAP_IS2_ACT_MIRROR_ENA]		= {  7,  1},
80362306a36Sopenharmony_ci	[VCAP_IS2_ACT_LRN_DIS]			= {  8,  1},
80462306a36Sopenharmony_ci	[VCAP_IS2_ACT_POLICE_ENA]		= {  9,  1},
80562306a36Sopenharmony_ci	[VCAP_IS2_ACT_POLICE_IDX]		= { 10,  9},
80662306a36Sopenharmony_ci	[VCAP_IS2_ACT_POLICE_VCAP_ONLY]		= { 19,  1},
80762306a36Sopenharmony_ci	[VCAP_IS2_ACT_PORT_MASK]		= { 20,  6},
80862306a36Sopenharmony_ci	[VCAP_IS2_ACT_REW_OP]			= { 26,  9},
80962306a36Sopenharmony_ci	[VCAP_IS2_ACT_SMAC_REPLACE_ENA]		= { 35,  1},
81062306a36Sopenharmony_ci	[VCAP_IS2_ACT_RSV]			= { 36,  2},
81162306a36Sopenharmony_ci	[VCAP_IS2_ACT_ACL_ID]			= { 38,  6},
81262306a36Sopenharmony_ci	[VCAP_IS2_ACT_HIT_CNT]			= { 44, 32},
81362306a36Sopenharmony_ci};
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic struct vcap_props vsc9959_vcap_props[] = {
81662306a36Sopenharmony_ci	[VCAP_ES0] = {
81762306a36Sopenharmony_ci		.action_type_width = 0,
81862306a36Sopenharmony_ci		.action_table = {
81962306a36Sopenharmony_ci			[ES0_ACTION_TYPE_NORMAL] = {
82062306a36Sopenharmony_ci				.width = 72, /* HIT_STICKY not included */
82162306a36Sopenharmony_ci				.count = 1,
82262306a36Sopenharmony_ci			},
82362306a36Sopenharmony_ci		},
82462306a36Sopenharmony_ci		.target = S0,
82562306a36Sopenharmony_ci		.keys = vsc9959_vcap_es0_keys,
82662306a36Sopenharmony_ci		.actions = vsc9959_vcap_es0_actions,
82762306a36Sopenharmony_ci	},
82862306a36Sopenharmony_ci	[VCAP_IS1] = {
82962306a36Sopenharmony_ci		.action_type_width = 0,
83062306a36Sopenharmony_ci		.action_table = {
83162306a36Sopenharmony_ci			[IS1_ACTION_TYPE_NORMAL] = {
83262306a36Sopenharmony_ci				.width = 78, /* HIT_STICKY not included */
83362306a36Sopenharmony_ci				.count = 4,
83462306a36Sopenharmony_ci			},
83562306a36Sopenharmony_ci		},
83662306a36Sopenharmony_ci		.target = S1,
83762306a36Sopenharmony_ci		.keys = vsc9959_vcap_is1_keys,
83862306a36Sopenharmony_ci		.actions = vsc9959_vcap_is1_actions,
83962306a36Sopenharmony_ci	},
84062306a36Sopenharmony_ci	[VCAP_IS2] = {
84162306a36Sopenharmony_ci		.action_type_width = 1,
84262306a36Sopenharmony_ci		.action_table = {
84362306a36Sopenharmony_ci			[IS2_ACTION_TYPE_NORMAL] = {
84462306a36Sopenharmony_ci				.width = 44,
84562306a36Sopenharmony_ci				.count = 2
84662306a36Sopenharmony_ci			},
84762306a36Sopenharmony_ci			[IS2_ACTION_TYPE_SMAC_SIP] = {
84862306a36Sopenharmony_ci				.width = 6,
84962306a36Sopenharmony_ci				.count = 4
85062306a36Sopenharmony_ci			},
85162306a36Sopenharmony_ci		},
85262306a36Sopenharmony_ci		.target = S2,
85362306a36Sopenharmony_ci		.keys = vsc9959_vcap_is2_keys,
85462306a36Sopenharmony_ci		.actions = vsc9959_vcap_is2_actions,
85562306a36Sopenharmony_ci	},
85662306a36Sopenharmony_ci};
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic const struct ptp_clock_info vsc9959_ptp_caps = {
85962306a36Sopenharmony_ci	.owner		= THIS_MODULE,
86062306a36Sopenharmony_ci	.name		= "felix ptp",
86162306a36Sopenharmony_ci	.max_adj	= 0x7fffffff,
86262306a36Sopenharmony_ci	.n_alarm	= 0,
86362306a36Sopenharmony_ci	.n_ext_ts	= 0,
86462306a36Sopenharmony_ci	.n_per_out	= OCELOT_PTP_PINS_NUM,
86562306a36Sopenharmony_ci	.n_pins		= OCELOT_PTP_PINS_NUM,
86662306a36Sopenharmony_ci	.pps		= 0,
86762306a36Sopenharmony_ci	.gettime64	= ocelot_ptp_gettime64,
86862306a36Sopenharmony_ci	.settime64	= ocelot_ptp_settime64,
86962306a36Sopenharmony_ci	.adjtime	= ocelot_ptp_adjtime,
87062306a36Sopenharmony_ci	.adjfine	= ocelot_ptp_adjfine,
87162306a36Sopenharmony_ci	.verify		= ocelot_ptp_verify,
87262306a36Sopenharmony_ci	.enable		= ocelot_ptp_enable,
87362306a36Sopenharmony_ci};
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci#define VSC9959_INIT_TIMEOUT			50000
87662306a36Sopenharmony_ci#define VSC9959_GCB_RST_SLEEP			100
87762306a36Sopenharmony_ci#define VSC9959_SYS_RAMINIT_SLEEP		80
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cistatic int vsc9959_gcb_soft_rst_status(struct ocelot *ocelot)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	int val;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	ocelot_field_read(ocelot, GCB_SOFT_RST_SWC_RST, &val);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return val;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic int vsc9959_sys_ram_init_status(struct ocelot *ocelot)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	return ocelot_read(ocelot, SYS_RAM_INIT);
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci/* CORE_ENA is in SYS:SYSTEM:RESET_CFG
89462306a36Sopenharmony_ci * RAM_INIT is in SYS:RAM_CTRL:RAM_INIT
89562306a36Sopenharmony_ci */
89662306a36Sopenharmony_cistatic int vsc9959_reset(struct ocelot *ocelot)
89762306a36Sopenharmony_ci{
89862306a36Sopenharmony_ci	int val, err;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	/* soft-reset the switch core */
90162306a36Sopenharmony_ci	ocelot_field_write(ocelot, GCB_SOFT_RST_SWC_RST, 1);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	err = readx_poll_timeout(vsc9959_gcb_soft_rst_status, ocelot, val, !val,
90462306a36Sopenharmony_ci				 VSC9959_GCB_RST_SLEEP, VSC9959_INIT_TIMEOUT);
90562306a36Sopenharmony_ci	if (err) {
90662306a36Sopenharmony_ci		dev_err(ocelot->dev, "timeout: switch core reset\n");
90762306a36Sopenharmony_ci		return err;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/* initialize switch mem ~40us */
91162306a36Sopenharmony_ci	ocelot_write(ocelot, SYS_RAM_INIT_RAM_INIT, SYS_RAM_INIT);
91262306a36Sopenharmony_ci	err = readx_poll_timeout(vsc9959_sys_ram_init_status, ocelot, val, !val,
91362306a36Sopenharmony_ci				 VSC9959_SYS_RAMINIT_SLEEP,
91462306a36Sopenharmony_ci				 VSC9959_INIT_TIMEOUT);
91562306a36Sopenharmony_ci	if (err) {
91662306a36Sopenharmony_ci		dev_err(ocelot->dev, "timeout: switch sram init\n");
91762306a36Sopenharmony_ci		return err;
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	/* enable switch core */
92162306a36Sopenharmony_ci	ocelot_field_write(ocelot, SYS_RESET_CFG_CORE_ENA, 1);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	return 0;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci/* Watermark encode
92762306a36Sopenharmony_ci * Bit 8:   Unit; 0:1, 1:16
92862306a36Sopenharmony_ci * Bit 7-0: Value to be multiplied with unit
92962306a36Sopenharmony_ci */
93062306a36Sopenharmony_cistatic u16 vsc9959_wm_enc(u16 value)
93162306a36Sopenharmony_ci{
93262306a36Sopenharmony_ci	WARN_ON(value >= 16 * BIT(8));
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	if (value >= BIT(8))
93562306a36Sopenharmony_ci		return BIT(8) | (value / 16);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	return value;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic u16 vsc9959_wm_dec(u16 wm)
94162306a36Sopenharmony_ci{
94262306a36Sopenharmony_ci	WARN_ON(wm & ~GENMASK(8, 0));
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	if (wm & BIT(8))
94562306a36Sopenharmony_ci		return (wm & GENMASK(7, 0)) * 16;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	return wm;
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic void vsc9959_wm_stat(u32 val, u32 *inuse, u32 *maxuse)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	*inuse = (val & GENMASK(23, 12)) >> 12;
95362306a36Sopenharmony_ci	*maxuse = val & GENMASK(11, 0);
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(ocelot->dev);
95962306a36Sopenharmony_ci	struct felix *felix = ocelot_to_felix(ocelot);
96062306a36Sopenharmony_ci	struct enetc_mdio_priv *mdio_priv;
96162306a36Sopenharmony_ci	struct device *dev = ocelot->dev;
96262306a36Sopenharmony_ci	resource_size_t imdio_base;
96362306a36Sopenharmony_ci	void __iomem *imdio_regs;
96462306a36Sopenharmony_ci	struct resource res;
96562306a36Sopenharmony_ci	struct enetc_hw *hw;
96662306a36Sopenharmony_ci	struct mii_bus *bus;
96762306a36Sopenharmony_ci	int port;
96862306a36Sopenharmony_ci	int rc;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
97162306a36Sopenharmony_ci				  sizeof(struct phylink_pcs *),
97262306a36Sopenharmony_ci				  GFP_KERNEL);
97362306a36Sopenharmony_ci	if (!felix->pcs) {
97462306a36Sopenharmony_ci		dev_err(dev, "failed to allocate array for PCS PHYs\n");
97562306a36Sopenharmony_ci		return -ENOMEM;
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	imdio_base = pci_resource_start(pdev, VSC9959_IMDIO_PCI_BAR);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	memcpy(&res, &vsc9959_imdio_res, sizeof(res));
98162306a36Sopenharmony_ci	res.start += imdio_base;
98262306a36Sopenharmony_ci	res.end += imdio_base;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	imdio_regs = devm_ioremap_resource(dev, &res);
98562306a36Sopenharmony_ci	if (IS_ERR(imdio_regs))
98662306a36Sopenharmony_ci		return PTR_ERR(imdio_regs);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	hw = enetc_hw_alloc(dev, imdio_regs);
98962306a36Sopenharmony_ci	if (IS_ERR(hw)) {
99062306a36Sopenharmony_ci		dev_err(dev, "failed to allocate ENETC HW structure\n");
99162306a36Sopenharmony_ci		return PTR_ERR(hw);
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
99562306a36Sopenharmony_ci	if (!bus)
99662306a36Sopenharmony_ci		return -ENOMEM;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	bus->name = "VSC9959 internal MDIO bus";
99962306a36Sopenharmony_ci	bus->read = enetc_mdio_read_c22;
100062306a36Sopenharmony_ci	bus->write = enetc_mdio_write_c22;
100162306a36Sopenharmony_ci	bus->read_c45 = enetc_mdio_read_c45;
100262306a36Sopenharmony_ci	bus->write_c45 = enetc_mdio_write_c45;
100362306a36Sopenharmony_ci	bus->parent = dev;
100462306a36Sopenharmony_ci	mdio_priv = bus->priv;
100562306a36Sopenharmony_ci	mdio_priv->hw = hw;
100662306a36Sopenharmony_ci	/* This gets added to imdio_regs, which already maps addresses
100762306a36Sopenharmony_ci	 * starting with the proper offset.
100862306a36Sopenharmony_ci	 */
100962306a36Sopenharmony_ci	mdio_priv->mdio_base = 0;
101062306a36Sopenharmony_ci	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev));
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	/* Needed in order to initialize the bus mutex lock */
101362306a36Sopenharmony_ci	rc = mdiobus_register(bus);
101462306a36Sopenharmony_ci	if (rc < 0) {
101562306a36Sopenharmony_ci		dev_err(dev, "failed to register MDIO bus\n");
101662306a36Sopenharmony_ci		mdiobus_free(bus);
101762306a36Sopenharmony_ci		return rc;
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	felix->imdio = bus;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	for (port = 0; port < felix->info->num_ports; port++) {
102362306a36Sopenharmony_ci		struct ocelot_port *ocelot_port = ocelot->ports[port];
102462306a36Sopenharmony_ci		struct phylink_pcs *phylink_pcs;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci		if (dsa_is_unused_port(felix->ds, port))
102762306a36Sopenharmony_ci			continue;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci		if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_INTERNAL)
103062306a36Sopenharmony_ci			continue;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci		phylink_pcs = lynx_pcs_create_mdiodev(felix->imdio, port);
103362306a36Sopenharmony_ci		if (IS_ERR(phylink_pcs))
103462306a36Sopenharmony_ci			continue;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci		felix->pcs[port] = phylink_pcs;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci		dev_info(dev, "Found PCS at internal MDIO address %d\n", port);
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	return 0;
104262306a36Sopenharmony_ci}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_cistatic void vsc9959_mdio_bus_free(struct ocelot *ocelot)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	struct felix *felix = ocelot_to_felix(ocelot);
104762306a36Sopenharmony_ci	int port;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	for (port = 0; port < ocelot->num_phys_ports; port++) {
105062306a36Sopenharmony_ci		struct phylink_pcs *phylink_pcs = felix->pcs[port];
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci		if (phylink_pcs)
105362306a36Sopenharmony_ci			lynx_pcs_destroy(phylink_pcs);
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci	mdiobus_unregister(felix->imdio);
105662306a36Sopenharmony_ci	mdiobus_free(felix->imdio);
105762306a36Sopenharmony_ci}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci/* The switch considers any frame (regardless of size) as eligible for
106062306a36Sopenharmony_ci * transmission if the traffic class gate is open for at least 33 ns.
106162306a36Sopenharmony_ci * Overruns are prevented by cropping an interval at the end of the gate time
106262306a36Sopenharmony_ci * slot for which egress scheduling is blocked, but we need to still keep 33 ns
106362306a36Sopenharmony_ci * available for one packet to be transmitted, otherwise the port tc will hang.
106462306a36Sopenharmony_ci * This function returns the size of a gate interval that remains available for
106562306a36Sopenharmony_ci * setting the guard band, after reserving the space for one egress frame.
106662306a36Sopenharmony_ci */
106762306a36Sopenharmony_cistatic u64 vsc9959_tas_remaining_gate_len_ps(u64 gate_len_ns)
106862306a36Sopenharmony_ci{
106962306a36Sopenharmony_ci	/* Gate always open */
107062306a36Sopenharmony_ci	if (gate_len_ns == U64_MAX)
107162306a36Sopenharmony_ci		return U64_MAX;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	if (gate_len_ns < VSC9959_TAS_MIN_GATE_LEN_NS)
107462306a36Sopenharmony_ci		return 0;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	return (gate_len_ns - VSC9959_TAS_MIN_GATE_LEN_NS) * PSEC_PER_NSEC;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci/* Extract shortest continuous gate open intervals in ns for each traffic class
108062306a36Sopenharmony_ci * of a cyclic tc-taprio schedule. If a gate is always open, the duration is
108162306a36Sopenharmony_ci * considered U64_MAX. If the gate is always closed, it is considered 0.
108262306a36Sopenharmony_ci */
108362306a36Sopenharmony_cistatic void vsc9959_tas_min_gate_lengths(struct tc_taprio_qopt_offload *taprio,
108462306a36Sopenharmony_ci					 u64 min_gate_len[OCELOT_NUM_TC])
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct tc_taprio_sched_entry *entry;
108762306a36Sopenharmony_ci	u64 gate_len[OCELOT_NUM_TC];
108862306a36Sopenharmony_ci	u8 gates_ever_opened = 0;
108962306a36Sopenharmony_ci	int tc, i, n;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	/* Initialize arrays */
109262306a36Sopenharmony_ci	for (tc = 0; tc < OCELOT_NUM_TC; tc++) {
109362306a36Sopenharmony_ci		min_gate_len[tc] = U64_MAX;
109462306a36Sopenharmony_ci		gate_len[tc] = 0;
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	/* If we don't have taprio, consider all gates as permanently open */
109862306a36Sopenharmony_ci	if (!taprio)
109962306a36Sopenharmony_ci		return;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	n = taprio->num_entries;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	/* Walk through the gate list twice to determine the length
110462306a36Sopenharmony_ci	 * of consecutively open gates for a traffic class, including
110562306a36Sopenharmony_ci	 * open gates that wrap around. We are just interested in the
110662306a36Sopenharmony_ci	 * minimum window size, and this doesn't change what the
110762306a36Sopenharmony_ci	 * minimum is (if the gate never closes, min_gate_len will
110862306a36Sopenharmony_ci	 * remain U64_MAX).
110962306a36Sopenharmony_ci	 */
111062306a36Sopenharmony_ci	for (i = 0; i < 2 * n; i++) {
111162306a36Sopenharmony_ci		entry = &taprio->entries[i % n];
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci		for (tc = 0; tc < OCELOT_NUM_TC; tc++) {
111462306a36Sopenharmony_ci			if (entry->gate_mask & BIT(tc)) {
111562306a36Sopenharmony_ci				gate_len[tc] += entry->interval;
111662306a36Sopenharmony_ci				gates_ever_opened |= BIT(tc);
111762306a36Sopenharmony_ci			} else {
111862306a36Sopenharmony_ci				/* Gate closes now, record a potential new
111962306a36Sopenharmony_ci				 * minimum and reinitialize length
112062306a36Sopenharmony_ci				 */
112162306a36Sopenharmony_ci				if (min_gate_len[tc] > gate_len[tc] &&
112262306a36Sopenharmony_ci				    gate_len[tc])
112362306a36Sopenharmony_ci					min_gate_len[tc] = gate_len[tc];
112462306a36Sopenharmony_ci				gate_len[tc] = 0;
112562306a36Sopenharmony_ci			}
112662306a36Sopenharmony_ci		}
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	/* min_gate_len[tc] actually tracks minimum *open* gate time, so for
113062306a36Sopenharmony_ci	 * permanently closed gates, min_gate_len[tc] will still be U64_MAX.
113162306a36Sopenharmony_ci	 * Therefore they are currently indistinguishable from permanently
113262306a36Sopenharmony_ci	 * open gates. Overwrite the gate len with 0 when we know they're
113362306a36Sopenharmony_ci	 * actually permanently closed, i.e. after the loop above.
113462306a36Sopenharmony_ci	 */
113562306a36Sopenharmony_ci	for (tc = 0; tc < OCELOT_NUM_TC; tc++)
113662306a36Sopenharmony_ci		if (!(gates_ever_opened & BIT(tc)))
113762306a36Sopenharmony_ci			min_gate_len[tc] = 0;
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci/* ocelot_write_rix is a macro that concatenates QSYS_MAXSDU_CFG_* with _RSZ,
114162306a36Sopenharmony_ci * so we need to spell out the register access to each traffic class in helper
114262306a36Sopenharmony_ci * functions, to simplify callers
114362306a36Sopenharmony_ci */
114462306a36Sopenharmony_cistatic void vsc9959_port_qmaxsdu_set(struct ocelot *ocelot, int port, int tc,
114562306a36Sopenharmony_ci				     u32 max_sdu)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	switch (tc) {
114862306a36Sopenharmony_ci	case 0:
114962306a36Sopenharmony_ci		ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_0,
115062306a36Sopenharmony_ci				 port);
115162306a36Sopenharmony_ci		break;
115262306a36Sopenharmony_ci	case 1:
115362306a36Sopenharmony_ci		ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_1,
115462306a36Sopenharmony_ci				 port);
115562306a36Sopenharmony_ci		break;
115662306a36Sopenharmony_ci	case 2:
115762306a36Sopenharmony_ci		ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_2,
115862306a36Sopenharmony_ci				 port);
115962306a36Sopenharmony_ci		break;
116062306a36Sopenharmony_ci	case 3:
116162306a36Sopenharmony_ci		ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_3,
116262306a36Sopenharmony_ci				 port);
116362306a36Sopenharmony_ci		break;
116462306a36Sopenharmony_ci	case 4:
116562306a36Sopenharmony_ci		ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_4,
116662306a36Sopenharmony_ci				 port);
116762306a36Sopenharmony_ci		break;
116862306a36Sopenharmony_ci	case 5:
116962306a36Sopenharmony_ci		ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_5,
117062306a36Sopenharmony_ci				 port);
117162306a36Sopenharmony_ci		break;
117262306a36Sopenharmony_ci	case 6:
117362306a36Sopenharmony_ci		ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_6,
117462306a36Sopenharmony_ci				 port);
117562306a36Sopenharmony_ci		break;
117662306a36Sopenharmony_ci	case 7:
117762306a36Sopenharmony_ci		ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_7,
117862306a36Sopenharmony_ci				 port);
117962306a36Sopenharmony_ci		break;
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic u32 vsc9959_port_qmaxsdu_get(struct ocelot *ocelot, int port, int tc)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	switch (tc) {
118662306a36Sopenharmony_ci	case 0: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_0, port);
118762306a36Sopenharmony_ci	case 1: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_1, port);
118862306a36Sopenharmony_ci	case 2: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_2, port);
118962306a36Sopenharmony_ci	case 3: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_3, port);
119062306a36Sopenharmony_ci	case 4: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_4, port);
119162306a36Sopenharmony_ci	case 5: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_5, port);
119262306a36Sopenharmony_ci	case 6: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_6, port);
119362306a36Sopenharmony_ci	case 7: return ocelot_read_rix(ocelot, QSYS_QMAXSDU_CFG_7, port);
119462306a36Sopenharmony_ci	default:
119562306a36Sopenharmony_ci		return 0;
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_cistatic u32 vsc9959_tas_tc_max_sdu(struct tc_taprio_qopt_offload *taprio, int tc)
120062306a36Sopenharmony_ci{
120162306a36Sopenharmony_ci	if (!taprio || !taprio->max_sdu[tc])
120262306a36Sopenharmony_ci		return 0;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	return taprio->max_sdu[tc] + ETH_HLEN + 2 * VLAN_HLEN + ETH_FCS_LEN;
120562306a36Sopenharmony_ci}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci/* Update QSYS_PORT_MAX_SDU to make sure the static guard bands added by the
120862306a36Sopenharmony_ci * switch (see the ALWAYS_GUARD_BAND_SCH_Q comment) are correct at all MTU
120962306a36Sopenharmony_ci * values (the default value is 1518). Also, for traffic class windows smaller
121062306a36Sopenharmony_ci * than one MTU sized frame, update QSYS_QMAXSDU_CFG to enable oversized frame
121162306a36Sopenharmony_ci * dropping, such that these won't hang the port, as they will never be sent.
121262306a36Sopenharmony_ci */
121362306a36Sopenharmony_cistatic void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	struct ocelot_port *ocelot_port = ocelot->ports[port];
121662306a36Sopenharmony_ci	struct ocelot_mm_state *mm = &ocelot->mm[port];
121762306a36Sopenharmony_ci	struct tc_taprio_qopt_offload *taprio;
121862306a36Sopenharmony_ci	u64 min_gate_len[OCELOT_NUM_TC];
121962306a36Sopenharmony_ci	u32 val, maxlen, add_frag_size;
122062306a36Sopenharmony_ci	u64 needed_min_frag_time_ps;
122162306a36Sopenharmony_ci	int speed, picos_per_byte;
122262306a36Sopenharmony_ci	u64 needed_bit_time_ps;
122362306a36Sopenharmony_ci	u8 tas_speed;
122462306a36Sopenharmony_ci	int tc;
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	lockdep_assert_held(&ocelot->fwd_domain_lock);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	taprio = ocelot_port->taprio;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port);
123162306a36Sopenharmony_ci	tas_speed = QSYS_TAG_CONFIG_LINK_SPEED_X(val);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	switch (tas_speed) {
123462306a36Sopenharmony_ci	case OCELOT_SPEED_10:
123562306a36Sopenharmony_ci		speed = SPEED_10;
123662306a36Sopenharmony_ci		break;
123762306a36Sopenharmony_ci	case OCELOT_SPEED_100:
123862306a36Sopenharmony_ci		speed = SPEED_100;
123962306a36Sopenharmony_ci		break;
124062306a36Sopenharmony_ci	case OCELOT_SPEED_1000:
124162306a36Sopenharmony_ci		speed = SPEED_1000;
124262306a36Sopenharmony_ci		break;
124362306a36Sopenharmony_ci	case OCELOT_SPEED_2500:
124462306a36Sopenharmony_ci		speed = SPEED_2500;
124562306a36Sopenharmony_ci		break;
124662306a36Sopenharmony_ci	default:
124762306a36Sopenharmony_ci		return;
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	picos_per_byte = (USEC_PER_SEC * 8) / speed;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	val = ocelot_port_readl(ocelot_port, DEV_MAC_MAXLEN_CFG);
125362306a36Sopenharmony_ci	/* MAXLEN_CFG accounts automatically for VLAN. We need to include it
125462306a36Sopenharmony_ci	 * manually in the bit time calculation, plus the preamble and SFD.
125562306a36Sopenharmony_ci	 */
125662306a36Sopenharmony_ci	maxlen = val + 2 * VLAN_HLEN;
125762306a36Sopenharmony_ci	/* Consider the standard Ethernet overhead of 8 octets preamble+SFD,
125862306a36Sopenharmony_ci	 * 4 octets FCS, 12 octets IFG.
125962306a36Sopenharmony_ci	 */
126062306a36Sopenharmony_ci	needed_bit_time_ps = (u64)(maxlen + 24) * picos_per_byte;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	/* Preemptible TCs don't need to pass a full MTU, the port will
126362306a36Sopenharmony_ci	 * automatically emit a HOLD request when a preemptible TC gate closes
126462306a36Sopenharmony_ci	 */
126562306a36Sopenharmony_ci	val = ocelot_read_rix(ocelot, QSYS_PREEMPTION_CFG, port);
126662306a36Sopenharmony_ci	add_frag_size = QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_X(val);
126762306a36Sopenharmony_ci	needed_min_frag_time_ps = picos_per_byte *
126862306a36Sopenharmony_ci		(u64)(24 + 2 * ethtool_mm_frag_size_add_to_min(add_frag_size));
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	dev_dbg(ocelot->dev,
127162306a36Sopenharmony_ci		"port %d: max frame size %d needs %llu ps, %llu ps for mPackets at speed %d\n",
127262306a36Sopenharmony_ci		port, maxlen, needed_bit_time_ps, needed_min_frag_time_ps,
127362306a36Sopenharmony_ci		speed);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	vsc9959_tas_min_gate_lengths(taprio, min_gate_len);
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	for (tc = 0; tc < OCELOT_NUM_TC; tc++) {
127862306a36Sopenharmony_ci		u32 requested_max_sdu = vsc9959_tas_tc_max_sdu(taprio, tc);
127962306a36Sopenharmony_ci		u64 remaining_gate_len_ps;
128062306a36Sopenharmony_ci		u32 max_sdu;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci		remaining_gate_len_ps =
128362306a36Sopenharmony_ci			vsc9959_tas_remaining_gate_len_ps(min_gate_len[tc]);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci		if ((mm->active_preemptible_tcs & BIT(tc)) ?
128662306a36Sopenharmony_ci		    remaining_gate_len_ps > needed_min_frag_time_ps :
128762306a36Sopenharmony_ci		    remaining_gate_len_ps > needed_bit_time_ps) {
128862306a36Sopenharmony_ci			/* Setting QMAXSDU_CFG to 0 disables oversized frame
128962306a36Sopenharmony_ci			 * dropping.
129062306a36Sopenharmony_ci			 */
129162306a36Sopenharmony_ci			max_sdu = requested_max_sdu;
129262306a36Sopenharmony_ci			dev_dbg(ocelot->dev,
129362306a36Sopenharmony_ci				"port %d tc %d min gate len %llu"
129462306a36Sopenharmony_ci				", sending all frames\n",
129562306a36Sopenharmony_ci				port, tc, min_gate_len[tc]);
129662306a36Sopenharmony_ci		} else {
129762306a36Sopenharmony_ci			/* If traffic class doesn't support a full MTU sized
129862306a36Sopenharmony_ci			 * frame, make sure to enable oversize frame dropping
129962306a36Sopenharmony_ci			 * for frames larger than the smallest that would fit.
130062306a36Sopenharmony_ci			 *
130162306a36Sopenharmony_ci			 * However, the exact same register, QSYS_QMAXSDU_CFG_*,
130262306a36Sopenharmony_ci			 * controls not only oversized frame dropping, but also
130362306a36Sopenharmony_ci			 * per-tc static guard band lengths, so it reduces the
130462306a36Sopenharmony_ci			 * useful gate interval length. Therefore, be careful
130562306a36Sopenharmony_ci			 * to calculate a guard band (and therefore max_sdu)
130662306a36Sopenharmony_ci			 * that still leaves 33 ns available in the time slot.
130762306a36Sopenharmony_ci			 */
130862306a36Sopenharmony_ci			max_sdu = div_u64(remaining_gate_len_ps, picos_per_byte);
130962306a36Sopenharmony_ci			/* A TC gate may be completely closed, which is a
131062306a36Sopenharmony_ci			 * special case where all packets are oversized.
131162306a36Sopenharmony_ci			 * Any limit smaller than 64 octets accomplishes this
131262306a36Sopenharmony_ci			 */
131362306a36Sopenharmony_ci			if (!max_sdu)
131462306a36Sopenharmony_ci				max_sdu = 1;
131562306a36Sopenharmony_ci			/* Take L1 overhead into account, but just don't allow
131662306a36Sopenharmony_ci			 * max_sdu to go negative or to 0. Here we use 20
131762306a36Sopenharmony_ci			 * because QSYS_MAXSDU_CFG_* already counts the 4 FCS
131862306a36Sopenharmony_ci			 * octets as part of packet size.
131962306a36Sopenharmony_ci			 */
132062306a36Sopenharmony_ci			if (max_sdu > 20)
132162306a36Sopenharmony_ci				max_sdu -= 20;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci			if (requested_max_sdu && requested_max_sdu < max_sdu)
132462306a36Sopenharmony_ci				max_sdu = requested_max_sdu;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci			dev_info(ocelot->dev,
132762306a36Sopenharmony_ci				 "port %d tc %d min gate length %llu"
132862306a36Sopenharmony_ci				 " ns not enough for max frame size %d at %d"
132962306a36Sopenharmony_ci				 " Mbps, dropping frames over %d"
133062306a36Sopenharmony_ci				 " octets including FCS\n",
133162306a36Sopenharmony_ci				 port, tc, min_gate_len[tc], maxlen, speed,
133262306a36Sopenharmony_ci				 max_sdu);
133362306a36Sopenharmony_ci		}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci		vsc9959_port_qmaxsdu_set(ocelot, port, tc, max_sdu);
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	ocelot_write_rix(ocelot, maxlen, QSYS_PORT_MAX_SDU, port);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	ocelot->ops->cut_through_fwd(ocelot);
134162306a36Sopenharmony_ci}
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_cistatic void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
134462306a36Sopenharmony_ci				    u32 speed)
134562306a36Sopenharmony_ci{
134662306a36Sopenharmony_ci	struct ocelot_port *ocelot_port = ocelot->ports[port];
134762306a36Sopenharmony_ci	u8 tas_speed;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	switch (speed) {
135062306a36Sopenharmony_ci	case SPEED_10:
135162306a36Sopenharmony_ci		tas_speed = OCELOT_SPEED_10;
135262306a36Sopenharmony_ci		break;
135362306a36Sopenharmony_ci	case SPEED_100:
135462306a36Sopenharmony_ci		tas_speed = OCELOT_SPEED_100;
135562306a36Sopenharmony_ci		break;
135662306a36Sopenharmony_ci	case SPEED_1000:
135762306a36Sopenharmony_ci		tas_speed = OCELOT_SPEED_1000;
135862306a36Sopenharmony_ci		break;
135962306a36Sopenharmony_ci	case SPEED_2500:
136062306a36Sopenharmony_ci		tas_speed = OCELOT_SPEED_2500;
136162306a36Sopenharmony_ci		break;
136262306a36Sopenharmony_ci	default:
136362306a36Sopenharmony_ci		tas_speed = OCELOT_SPEED_1000;
136462306a36Sopenharmony_ci		break;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	mutex_lock(&ocelot->fwd_domain_lock);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	ocelot_rmw_rix(ocelot,
137062306a36Sopenharmony_ci		       QSYS_TAG_CONFIG_LINK_SPEED(tas_speed),
137162306a36Sopenharmony_ci		       QSYS_TAG_CONFIG_LINK_SPEED_M,
137262306a36Sopenharmony_ci		       QSYS_TAG_CONFIG, port);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	if (ocelot_port->taprio)
137562306a36Sopenharmony_ci		vsc9959_tas_guard_bands_update(ocelot, port);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	mutex_unlock(&ocelot->fwd_domain_lock);
137862306a36Sopenharmony_ci}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_cistatic void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time,
138162306a36Sopenharmony_ci				  u64 cycle_time,
138262306a36Sopenharmony_ci				  struct timespec64 *new_base_ts)
138362306a36Sopenharmony_ci{
138462306a36Sopenharmony_ci	struct timespec64 ts;
138562306a36Sopenharmony_ci	ktime_t new_base_time;
138662306a36Sopenharmony_ci	ktime_t current_time;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
138962306a36Sopenharmony_ci	current_time = timespec64_to_ktime(ts);
139062306a36Sopenharmony_ci	new_base_time = base_time;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	if (base_time < current_time) {
139362306a36Sopenharmony_ci		u64 nr_of_cycles = current_time - base_time;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci		do_div(nr_of_cycles, cycle_time);
139662306a36Sopenharmony_ci		new_base_time += cycle_time * (nr_of_cycles + 1);
139762306a36Sopenharmony_ci	}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	*new_base_ts = ktime_to_timespec64(new_base_time);
140062306a36Sopenharmony_ci}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_cistatic u32 vsc9959_tas_read_cfg_status(struct ocelot *ocelot)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci	return ocelot_read(ocelot, QSYS_TAS_PARAM_CFG_CTRL);
140562306a36Sopenharmony_ci}
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_cistatic void vsc9959_tas_gcl_set(struct ocelot *ocelot, const u32 gcl_ix,
140862306a36Sopenharmony_ci				struct tc_taprio_sched_entry *entry)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	ocelot_write(ocelot,
141162306a36Sopenharmony_ci		     QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(gcl_ix) |
141262306a36Sopenharmony_ci		     QSYS_GCL_CFG_REG_1_GATE_STATE(entry->gate_mask),
141362306a36Sopenharmony_ci		     QSYS_GCL_CFG_REG_1);
141462306a36Sopenharmony_ci	ocelot_write(ocelot, entry->interval, QSYS_GCL_CFG_REG_2);
141562306a36Sopenharmony_ci}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_cistatic int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port,
141862306a36Sopenharmony_ci				    struct tc_taprio_qopt_offload *taprio)
141962306a36Sopenharmony_ci{
142062306a36Sopenharmony_ci	struct ocelot_port *ocelot_port = ocelot->ports[port];
142162306a36Sopenharmony_ci	struct timespec64 base_ts;
142262306a36Sopenharmony_ci	int ret, i;
142362306a36Sopenharmony_ci	u32 val;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	mutex_lock(&ocelot->fwd_domain_lock);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	if (taprio->cmd == TAPRIO_CMD_DESTROY) {
142862306a36Sopenharmony_ci		ocelot_port_mqprio(ocelot, port, &taprio->mqprio);
142962306a36Sopenharmony_ci		ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE,
143062306a36Sopenharmony_ci			       QSYS_TAG_CONFIG, port);
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci		taprio_offload_free(ocelot_port->taprio);
143362306a36Sopenharmony_ci		ocelot_port->taprio = NULL;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci		vsc9959_tas_guard_bands_update(ocelot, port);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci		mutex_unlock(&ocelot->fwd_domain_lock);
143862306a36Sopenharmony_ci		return 0;
143962306a36Sopenharmony_ci	} else if (taprio->cmd != TAPRIO_CMD_REPLACE) {
144062306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
144162306a36Sopenharmony_ci		goto err_unlock;
144262306a36Sopenharmony_ci	}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	ret = ocelot_port_mqprio(ocelot, port, &taprio->mqprio);
144562306a36Sopenharmony_ci	if (ret)
144662306a36Sopenharmony_ci		goto err_unlock;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	if (taprio->cycle_time > NSEC_PER_SEC ||
144962306a36Sopenharmony_ci	    taprio->cycle_time_extension >= NSEC_PER_SEC) {
145062306a36Sopenharmony_ci		ret = -EINVAL;
145162306a36Sopenharmony_ci		goto err_reset_tc;
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX) {
145562306a36Sopenharmony_ci		ret = -ERANGE;
145662306a36Sopenharmony_ci		goto err_reset_tc;
145762306a36Sopenharmony_ci	}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	/* Enable guard band. The switch will schedule frames without taking
146062306a36Sopenharmony_ci	 * their length into account. Thus we'll always need to enable the
146162306a36Sopenharmony_ci	 * guard band which reserves the time of a maximum sized frame at the
146262306a36Sopenharmony_ci	 * end of the time window.
146362306a36Sopenharmony_ci	 *
146462306a36Sopenharmony_ci	 * Although the ALWAYS_GUARD_BAND_SCH_Q bit is global for all ports, we
146562306a36Sopenharmony_ci	 * need to set PORT_NUM, because subsequent writes to PARAM_CFG_REG_n
146662306a36Sopenharmony_ci	 * operate on the port number.
146762306a36Sopenharmony_ci	 */
146862306a36Sopenharmony_ci	ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port) |
146962306a36Sopenharmony_ci		   QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q,
147062306a36Sopenharmony_ci		   QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M |
147162306a36Sopenharmony_ci		   QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q,
147262306a36Sopenharmony_ci		   QSYS_TAS_PARAM_CFG_CTRL);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	/* Hardware errata -  Admin config could not be overwritten if
147562306a36Sopenharmony_ci	 * config is pending, need reset the TAS module
147662306a36Sopenharmony_ci	 */
147762306a36Sopenharmony_ci	val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
147862306a36Sopenharmony_ci	if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) {
147962306a36Sopenharmony_ci		ret = -EBUSY;
148062306a36Sopenharmony_ci		goto err_reset_tc;
148162306a36Sopenharmony_ci	}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	ocelot_rmw_rix(ocelot,
148462306a36Sopenharmony_ci		       QSYS_TAG_CONFIG_ENABLE |
148562306a36Sopenharmony_ci		       QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF) |
148662306a36Sopenharmony_ci		       QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(0xFF),
148762306a36Sopenharmony_ci		       QSYS_TAG_CONFIG_ENABLE |
148862306a36Sopenharmony_ci		       QSYS_TAG_CONFIG_INIT_GATE_STATE_M |
148962306a36Sopenharmony_ci		       QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M,
149062306a36Sopenharmony_ci		       QSYS_TAG_CONFIG, port);
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	vsc9959_new_base_time(ocelot, taprio->base_time,
149362306a36Sopenharmony_ci			      taprio->cycle_time, &base_ts);
149462306a36Sopenharmony_ci	ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1);
149562306a36Sopenharmony_ci	ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec), QSYS_PARAM_CFG_REG_2);
149662306a36Sopenharmony_ci	val = upper_32_bits(base_ts.tv_sec);
149762306a36Sopenharmony_ci	ocelot_write(ocelot,
149862306a36Sopenharmony_ci		     QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val) |
149962306a36Sopenharmony_ci		     QSYS_PARAM_CFG_REG_3_LIST_LENGTH(taprio->num_entries),
150062306a36Sopenharmony_ci		     QSYS_PARAM_CFG_REG_3);
150162306a36Sopenharmony_ci	ocelot_write(ocelot, taprio->cycle_time, QSYS_PARAM_CFG_REG_4);
150262306a36Sopenharmony_ci	ocelot_write(ocelot, taprio->cycle_time_extension, QSYS_PARAM_CFG_REG_5);
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	for (i = 0; i < taprio->num_entries; i++)
150562306a36Sopenharmony_ci		vsc9959_tas_gcl_set(ocelot, i, &taprio->entries[i]);
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
150862306a36Sopenharmony_ci		   QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
150962306a36Sopenharmony_ci		   QSYS_TAS_PARAM_CFG_CTRL);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	ret = readx_poll_timeout(vsc9959_tas_read_cfg_status, ocelot, val,
151262306a36Sopenharmony_ci				 !(val & QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE),
151362306a36Sopenharmony_ci				 10, 100000);
151462306a36Sopenharmony_ci	if (ret)
151562306a36Sopenharmony_ci		goto err_reset_tc;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	ocelot_port->taprio = taprio_offload_get(taprio);
151862306a36Sopenharmony_ci	vsc9959_tas_guard_bands_update(ocelot, port);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	mutex_unlock(&ocelot->fwd_domain_lock);
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	return 0;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_cierr_reset_tc:
152562306a36Sopenharmony_ci	taprio->mqprio.qopt.num_tc = 0;
152662306a36Sopenharmony_ci	ocelot_port_mqprio(ocelot, port, &taprio->mqprio);
152762306a36Sopenharmony_cierr_unlock:
152862306a36Sopenharmony_ci	mutex_unlock(&ocelot->fwd_domain_lock);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	return ret;
153162306a36Sopenharmony_ci}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_cistatic void vsc9959_tas_clock_adjust(struct ocelot *ocelot)
153462306a36Sopenharmony_ci{
153562306a36Sopenharmony_ci	struct tc_taprio_qopt_offload *taprio;
153662306a36Sopenharmony_ci	struct ocelot_port *ocelot_port;
153762306a36Sopenharmony_ci	struct timespec64 base_ts;
153862306a36Sopenharmony_ci	int port;
153962306a36Sopenharmony_ci	u32 val;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	mutex_lock(&ocelot->fwd_domain_lock);
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	for (port = 0; port < ocelot->num_phys_ports; port++) {
154462306a36Sopenharmony_ci		ocelot_port = ocelot->ports[port];
154562306a36Sopenharmony_ci		taprio = ocelot_port->taprio;
154662306a36Sopenharmony_ci		if (!taprio)
154762306a36Sopenharmony_ci			continue;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci		ocelot_rmw(ocelot,
155062306a36Sopenharmony_ci			   QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port),
155162306a36Sopenharmony_ci			   QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
155262306a36Sopenharmony_ci			   QSYS_TAS_PARAM_CFG_CTRL);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci		/* Disable time-aware shaper */
155562306a36Sopenharmony_ci		ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE,
155662306a36Sopenharmony_ci			       QSYS_TAG_CONFIG, port);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci		vsc9959_new_base_time(ocelot, taprio->base_time,
155962306a36Sopenharmony_ci				      taprio->cycle_time, &base_ts);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci		ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1);
156262306a36Sopenharmony_ci		ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec),
156362306a36Sopenharmony_ci			     QSYS_PARAM_CFG_REG_2);
156462306a36Sopenharmony_ci		val = upper_32_bits(base_ts.tv_sec);
156562306a36Sopenharmony_ci		ocelot_rmw(ocelot,
156662306a36Sopenharmony_ci			   QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val),
156762306a36Sopenharmony_ci			   QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M,
156862306a36Sopenharmony_ci			   QSYS_PARAM_CFG_REG_3);
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci		ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
157162306a36Sopenharmony_ci			   QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
157262306a36Sopenharmony_ci			   QSYS_TAS_PARAM_CFG_CTRL);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci		/* Re-enable time-aware shaper */
157562306a36Sopenharmony_ci		ocelot_rmw_rix(ocelot, QSYS_TAG_CONFIG_ENABLE,
157662306a36Sopenharmony_ci			       QSYS_TAG_CONFIG_ENABLE,
157762306a36Sopenharmony_ci			       QSYS_TAG_CONFIG, port);
157862306a36Sopenharmony_ci	}
157962306a36Sopenharmony_ci	mutex_unlock(&ocelot->fwd_domain_lock);
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_cistatic int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port,
158362306a36Sopenharmony_ci				    struct tc_cbs_qopt_offload *cbs_qopt)
158462306a36Sopenharmony_ci{
158562306a36Sopenharmony_ci	struct ocelot *ocelot = ds->priv;
158662306a36Sopenharmony_ci	int port_ix = port * 8 + cbs_qopt->queue;
158762306a36Sopenharmony_ci	u32 rate, burst;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	if (cbs_qopt->queue >= ds->num_tx_queues)
159062306a36Sopenharmony_ci		return -EINVAL;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	if (!cbs_qopt->enable) {
159362306a36Sopenharmony_ci		ocelot_write_gix(ocelot, QSYS_CIR_CFG_CIR_RATE(0) |
159462306a36Sopenharmony_ci				 QSYS_CIR_CFG_CIR_BURST(0),
159562306a36Sopenharmony_ci				 QSYS_CIR_CFG, port_ix);
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci		ocelot_rmw_gix(ocelot, 0, QSYS_SE_CFG_SE_AVB_ENA,
159862306a36Sopenharmony_ci			       QSYS_SE_CFG, port_ix);
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci		return 0;
160162306a36Sopenharmony_ci	}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	/* Rate unit is 100 kbps */
160462306a36Sopenharmony_ci	rate = DIV_ROUND_UP(cbs_qopt->idleslope, 100);
160562306a36Sopenharmony_ci	/* Avoid using zero rate */
160662306a36Sopenharmony_ci	rate = clamp_t(u32, rate, 1, GENMASK(14, 0));
160762306a36Sopenharmony_ci	/* Burst unit is 4kB */
160862306a36Sopenharmony_ci	burst = DIV_ROUND_UP(cbs_qopt->hicredit, 4096);
160962306a36Sopenharmony_ci	/* Avoid using zero burst size */
161062306a36Sopenharmony_ci	burst = clamp_t(u32, burst, 1, GENMASK(5, 0));
161162306a36Sopenharmony_ci	ocelot_write_gix(ocelot,
161262306a36Sopenharmony_ci			 QSYS_CIR_CFG_CIR_RATE(rate) |
161362306a36Sopenharmony_ci			 QSYS_CIR_CFG_CIR_BURST(burst),
161462306a36Sopenharmony_ci			 QSYS_CIR_CFG,
161562306a36Sopenharmony_ci			 port_ix);
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	ocelot_rmw_gix(ocelot,
161862306a36Sopenharmony_ci		       QSYS_SE_CFG_SE_FRM_MODE(0) |
161962306a36Sopenharmony_ci		       QSYS_SE_CFG_SE_AVB_ENA,
162062306a36Sopenharmony_ci		       QSYS_SE_CFG_SE_AVB_ENA |
162162306a36Sopenharmony_ci		       QSYS_SE_CFG_SE_FRM_MODE_M,
162262306a36Sopenharmony_ci		       QSYS_SE_CFG,
162362306a36Sopenharmony_ci		       port_ix);
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	return 0;
162662306a36Sopenharmony_ci}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_cistatic int vsc9959_qos_query_caps(struct tc_query_caps_base *base)
162962306a36Sopenharmony_ci{
163062306a36Sopenharmony_ci	switch (base->type) {
163162306a36Sopenharmony_ci	case TC_SETUP_QDISC_MQPRIO: {
163262306a36Sopenharmony_ci		struct tc_mqprio_caps *caps = base->caps;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci		caps->validate_queue_counts = true;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci		return 0;
163762306a36Sopenharmony_ci	}
163862306a36Sopenharmony_ci	case TC_SETUP_QDISC_TAPRIO: {
163962306a36Sopenharmony_ci		struct tc_taprio_caps *caps = base->caps;
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci		caps->supports_queue_max_sdu = true;
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci		return 0;
164462306a36Sopenharmony_ci	}
164562306a36Sopenharmony_ci	default:
164662306a36Sopenharmony_ci		return -EOPNOTSUPP;
164762306a36Sopenharmony_ci	}
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cistatic int vsc9959_qos_port_mqprio(struct ocelot *ocelot, int port,
165162306a36Sopenharmony_ci				   struct tc_mqprio_qopt_offload *mqprio)
165262306a36Sopenharmony_ci{
165362306a36Sopenharmony_ci	int ret;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	mutex_lock(&ocelot->fwd_domain_lock);
165662306a36Sopenharmony_ci	ret = ocelot_port_mqprio(ocelot, port, mqprio);
165762306a36Sopenharmony_ci	mutex_unlock(&ocelot->fwd_domain_lock);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	return ret;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_cistatic int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
166362306a36Sopenharmony_ci				 enum tc_setup_type type,
166462306a36Sopenharmony_ci				 void *type_data)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	struct ocelot *ocelot = ds->priv;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	switch (type) {
166962306a36Sopenharmony_ci	case TC_QUERY_CAPS:
167062306a36Sopenharmony_ci		return vsc9959_qos_query_caps(type_data);
167162306a36Sopenharmony_ci	case TC_SETUP_QDISC_TAPRIO:
167262306a36Sopenharmony_ci		return vsc9959_qos_port_tas_set(ocelot, port, type_data);
167362306a36Sopenharmony_ci	case TC_SETUP_QDISC_MQPRIO:
167462306a36Sopenharmony_ci		return vsc9959_qos_port_mqprio(ocelot, port, type_data);
167562306a36Sopenharmony_ci	case TC_SETUP_QDISC_CBS:
167662306a36Sopenharmony_ci		return vsc9959_qos_port_cbs_set(ds, port, type_data);
167762306a36Sopenharmony_ci	default:
167862306a36Sopenharmony_ci		return -EOPNOTSUPP;
167962306a36Sopenharmony_ci	}
168062306a36Sopenharmony_ci}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci#define VSC9959_PSFP_SFID_MAX			175
168362306a36Sopenharmony_ci#define VSC9959_PSFP_GATE_ID_MAX		183
168462306a36Sopenharmony_ci#define VSC9959_PSFP_POLICER_BASE		63
168562306a36Sopenharmony_ci#define VSC9959_PSFP_POLICER_MAX		383
168662306a36Sopenharmony_ci#define VSC9959_PSFP_GATE_LIST_NUM		4
168762306a36Sopenharmony_ci#define VSC9959_PSFP_GATE_CYCLETIME_MIN		5000
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_cistruct felix_stream {
169062306a36Sopenharmony_ci	struct list_head list;
169162306a36Sopenharmony_ci	unsigned long id;
169262306a36Sopenharmony_ci	bool dummy;
169362306a36Sopenharmony_ci	int ports;
169462306a36Sopenharmony_ci	int port;
169562306a36Sopenharmony_ci	u8 dmac[ETH_ALEN];
169662306a36Sopenharmony_ci	u16 vid;
169762306a36Sopenharmony_ci	s8 prio;
169862306a36Sopenharmony_ci	u8 sfid_valid;
169962306a36Sopenharmony_ci	u8 ssid_valid;
170062306a36Sopenharmony_ci	u32 sfid;
170162306a36Sopenharmony_ci	u32 ssid;
170262306a36Sopenharmony_ci};
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_cistruct felix_stream_filter_counters {
170562306a36Sopenharmony_ci	u64 match;
170662306a36Sopenharmony_ci	u64 not_pass_gate;
170762306a36Sopenharmony_ci	u64 not_pass_sdu;
170862306a36Sopenharmony_ci	u64 red;
170962306a36Sopenharmony_ci};
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cistruct felix_stream_filter {
171262306a36Sopenharmony_ci	struct felix_stream_filter_counters stats;
171362306a36Sopenharmony_ci	struct list_head list;
171462306a36Sopenharmony_ci	refcount_t refcount;
171562306a36Sopenharmony_ci	u32 index;
171662306a36Sopenharmony_ci	u8 enable;
171762306a36Sopenharmony_ci	int portmask;
171862306a36Sopenharmony_ci	u8 sg_valid;
171962306a36Sopenharmony_ci	u32 sgid;
172062306a36Sopenharmony_ci	u8 fm_valid;
172162306a36Sopenharmony_ci	u32 fmid;
172262306a36Sopenharmony_ci	u8 prio_valid;
172362306a36Sopenharmony_ci	u8 prio;
172462306a36Sopenharmony_ci	u32 maxsdu;
172562306a36Sopenharmony_ci};
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_cistruct felix_stream_gate {
172862306a36Sopenharmony_ci	u32 index;
172962306a36Sopenharmony_ci	u8 enable;
173062306a36Sopenharmony_ci	u8 ipv_valid;
173162306a36Sopenharmony_ci	u8 init_ipv;
173262306a36Sopenharmony_ci	u64 basetime;
173362306a36Sopenharmony_ci	u64 cycletime;
173462306a36Sopenharmony_ci	u64 cycletime_ext;
173562306a36Sopenharmony_ci	u32 num_entries;
173662306a36Sopenharmony_ci	struct action_gate_entry entries[];
173762306a36Sopenharmony_ci};
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_cistruct felix_stream_gate_entry {
174062306a36Sopenharmony_ci	struct list_head list;
174162306a36Sopenharmony_ci	refcount_t refcount;
174262306a36Sopenharmony_ci	u32 index;
174362306a36Sopenharmony_ci};
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_cistatic int vsc9959_stream_identify(struct flow_cls_offload *f,
174662306a36Sopenharmony_ci				   struct felix_stream *stream)
174762306a36Sopenharmony_ci{
174862306a36Sopenharmony_ci	struct flow_rule *rule = flow_cls_offload_flow_rule(f);
174962306a36Sopenharmony_ci	struct flow_dissector *dissector = rule->match.dissector;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	if (dissector->used_keys &
175262306a36Sopenharmony_ci	    ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
175362306a36Sopenharmony_ci	      BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
175462306a36Sopenharmony_ci	      BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
175562306a36Sopenharmony_ci	      BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS)))
175662306a36Sopenharmony_ci		return -EOPNOTSUPP;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
175962306a36Sopenharmony_ci		struct flow_match_eth_addrs match;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci		flow_rule_match_eth_addrs(rule, &match);
176262306a36Sopenharmony_ci		ether_addr_copy(stream->dmac, match.key->dst);
176362306a36Sopenharmony_ci		if (!is_zero_ether_addr(match.mask->src))
176462306a36Sopenharmony_ci			return -EOPNOTSUPP;
176562306a36Sopenharmony_ci	} else {
176662306a36Sopenharmony_ci		return -EOPNOTSUPP;
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
177062306a36Sopenharmony_ci		struct flow_match_vlan match;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci		flow_rule_match_vlan(rule, &match);
177362306a36Sopenharmony_ci		if (match.mask->vlan_priority)
177462306a36Sopenharmony_ci			stream->prio = match.key->vlan_priority;
177562306a36Sopenharmony_ci		else
177662306a36Sopenharmony_ci			stream->prio = -1;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci		if (!match.mask->vlan_id)
177962306a36Sopenharmony_ci			return -EOPNOTSUPP;
178062306a36Sopenharmony_ci		stream->vid = match.key->vlan_id;
178162306a36Sopenharmony_ci	} else {
178262306a36Sopenharmony_ci		return -EOPNOTSUPP;
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	stream->id = f->cookie;
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	return 0;
178862306a36Sopenharmony_ci}
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_cistatic int vsc9959_mact_stream_set(struct ocelot *ocelot,
179162306a36Sopenharmony_ci				   struct felix_stream *stream,
179262306a36Sopenharmony_ci				   struct netlink_ext_ack *extack)
179362306a36Sopenharmony_ci{
179462306a36Sopenharmony_ci	enum macaccess_entry_type type;
179562306a36Sopenharmony_ci	int ret, sfid, ssid;
179662306a36Sopenharmony_ci	u32 vid, dst_idx;
179762306a36Sopenharmony_ci	u8 mac[ETH_ALEN];
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	ether_addr_copy(mac, stream->dmac);
180062306a36Sopenharmony_ci	vid = stream->vid;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	/* Stream identification desn't support to add a stream with non
180362306a36Sopenharmony_ci	 * existent MAC (The MAC entry has not been learned in MAC table).
180462306a36Sopenharmony_ci	 */
180562306a36Sopenharmony_ci	ret = ocelot_mact_lookup(ocelot, &dst_idx, mac, vid, &type);
180662306a36Sopenharmony_ci	if (ret) {
180762306a36Sopenharmony_ci		if (extack)
180862306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Stream is not learned in MAC table");
180962306a36Sopenharmony_ci		return -EOPNOTSUPP;
181062306a36Sopenharmony_ci	}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	if ((stream->sfid_valid || stream->ssid_valid) &&
181362306a36Sopenharmony_ci	    type == ENTRYTYPE_NORMAL)
181462306a36Sopenharmony_ci		type = ENTRYTYPE_LOCKED;
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	sfid = stream->sfid_valid ? stream->sfid : -1;
181762306a36Sopenharmony_ci	ssid = stream->ssid_valid ? stream->ssid : -1;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	ret = ocelot_mact_learn_streamdata(ocelot, dst_idx, mac, vid, type,
182062306a36Sopenharmony_ci					   sfid, ssid);
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	return ret;
182362306a36Sopenharmony_ci}
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_cistatic struct felix_stream *
182662306a36Sopenharmony_civsc9959_stream_table_lookup(struct list_head *stream_list,
182762306a36Sopenharmony_ci			    struct felix_stream *stream)
182862306a36Sopenharmony_ci{
182962306a36Sopenharmony_ci	struct felix_stream *tmp;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	list_for_each_entry(tmp, stream_list, list)
183262306a36Sopenharmony_ci		if (ether_addr_equal(tmp->dmac, stream->dmac) &&
183362306a36Sopenharmony_ci		    tmp->vid == stream->vid)
183462306a36Sopenharmony_ci			return tmp;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	return NULL;
183762306a36Sopenharmony_ci}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_cistatic int vsc9959_stream_table_add(struct ocelot *ocelot,
184062306a36Sopenharmony_ci				    struct list_head *stream_list,
184162306a36Sopenharmony_ci				    struct felix_stream *stream,
184262306a36Sopenharmony_ci				    struct netlink_ext_ack *extack)
184362306a36Sopenharmony_ci{
184462306a36Sopenharmony_ci	struct felix_stream *stream_entry;
184562306a36Sopenharmony_ci	int ret;
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	stream_entry = kmemdup(stream, sizeof(*stream_entry), GFP_KERNEL);
184862306a36Sopenharmony_ci	if (!stream_entry)
184962306a36Sopenharmony_ci		return -ENOMEM;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	if (!stream->dummy) {
185262306a36Sopenharmony_ci		ret = vsc9959_mact_stream_set(ocelot, stream_entry, extack);
185362306a36Sopenharmony_ci		if (ret) {
185462306a36Sopenharmony_ci			kfree(stream_entry);
185562306a36Sopenharmony_ci			return ret;
185662306a36Sopenharmony_ci		}
185762306a36Sopenharmony_ci	}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	list_add_tail(&stream_entry->list, stream_list);
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	return 0;
186262306a36Sopenharmony_ci}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_cistatic struct felix_stream *
186562306a36Sopenharmony_civsc9959_stream_table_get(struct list_head *stream_list, unsigned long id)
186662306a36Sopenharmony_ci{
186762306a36Sopenharmony_ci	struct felix_stream *tmp;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	list_for_each_entry(tmp, stream_list, list)
187062306a36Sopenharmony_ci		if (tmp->id == id)
187162306a36Sopenharmony_ci			return tmp;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	return NULL;
187462306a36Sopenharmony_ci}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_cistatic void vsc9959_stream_table_del(struct ocelot *ocelot,
187762306a36Sopenharmony_ci				     struct felix_stream *stream)
187862306a36Sopenharmony_ci{
187962306a36Sopenharmony_ci	if (!stream->dummy)
188062306a36Sopenharmony_ci		vsc9959_mact_stream_set(ocelot, stream, NULL);
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	list_del(&stream->list);
188362306a36Sopenharmony_ci	kfree(stream);
188462306a36Sopenharmony_ci}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_cistatic u32 vsc9959_sfi_access_status(struct ocelot *ocelot)
188762306a36Sopenharmony_ci{
188862306a36Sopenharmony_ci	return ocelot_read(ocelot, ANA_TABLES_SFIDACCESS);
188962306a36Sopenharmony_ci}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_cistatic int vsc9959_psfp_sfi_set(struct ocelot *ocelot,
189262306a36Sopenharmony_ci				struct felix_stream_filter *sfi)
189362306a36Sopenharmony_ci{
189462306a36Sopenharmony_ci	u32 val;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	if (sfi->index > VSC9959_PSFP_SFID_MAX)
189762306a36Sopenharmony_ci		return -EINVAL;
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	if (!sfi->enable) {
190062306a36Sopenharmony_ci		ocelot_write(ocelot, ANA_TABLES_SFIDTIDX_SFID_INDEX(sfi->index),
190162306a36Sopenharmony_ci			     ANA_TABLES_SFIDTIDX);
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci		val = ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE);
190462306a36Sopenharmony_ci		ocelot_write(ocelot, val, ANA_TABLES_SFIDACCESS);
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci		return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val,
190762306a36Sopenharmony_ci					  (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)),
190862306a36Sopenharmony_ci					  10, 100000);
190962306a36Sopenharmony_ci	}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	if (sfi->sgid > VSC9959_PSFP_GATE_ID_MAX ||
191262306a36Sopenharmony_ci	    sfi->fmid > VSC9959_PSFP_POLICER_MAX)
191362306a36Sopenharmony_ci		return -EINVAL;
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	ocelot_write(ocelot,
191662306a36Sopenharmony_ci		     (sfi->sg_valid ? ANA_TABLES_SFIDTIDX_SGID_VALID : 0) |
191762306a36Sopenharmony_ci		     ANA_TABLES_SFIDTIDX_SGID(sfi->sgid) |
191862306a36Sopenharmony_ci		     (sfi->fm_valid ? ANA_TABLES_SFIDTIDX_POL_ENA : 0) |
191962306a36Sopenharmony_ci		     ANA_TABLES_SFIDTIDX_POL_IDX(sfi->fmid) |
192062306a36Sopenharmony_ci		     ANA_TABLES_SFIDTIDX_SFID_INDEX(sfi->index),
192162306a36Sopenharmony_ci		     ANA_TABLES_SFIDTIDX);
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	ocelot_write(ocelot,
192462306a36Sopenharmony_ci		     (sfi->prio_valid ? ANA_TABLES_SFIDACCESS_IGR_PRIO_MATCH_ENA : 0) |
192562306a36Sopenharmony_ci		     ANA_TABLES_SFIDACCESS_IGR_PRIO(sfi->prio) |
192662306a36Sopenharmony_ci		     ANA_TABLES_SFIDACCESS_MAX_SDU_LEN(sfi->maxsdu) |
192762306a36Sopenharmony_ci		     ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE),
192862306a36Sopenharmony_ci		     ANA_TABLES_SFIDACCESS);
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val,
193162306a36Sopenharmony_ci				  (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)),
193262306a36Sopenharmony_ci				  10, 100000);
193362306a36Sopenharmony_ci}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_cistatic int vsc9959_psfp_sfidmask_set(struct ocelot *ocelot, u32 sfid, int ports)
193662306a36Sopenharmony_ci{
193762306a36Sopenharmony_ci	u32 val;
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	ocelot_rmw(ocelot,
194062306a36Sopenharmony_ci		   ANA_TABLES_SFIDTIDX_SFID_INDEX(sfid),
194162306a36Sopenharmony_ci		   ANA_TABLES_SFIDTIDX_SFID_INDEX_M,
194262306a36Sopenharmony_ci		   ANA_TABLES_SFIDTIDX);
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	ocelot_write(ocelot,
194562306a36Sopenharmony_ci		     ANA_TABLES_SFID_MASK_IGR_PORT_MASK(ports) |
194662306a36Sopenharmony_ci		     ANA_TABLES_SFID_MASK_IGR_SRCPORT_MATCH_ENA,
194762306a36Sopenharmony_ci		     ANA_TABLES_SFID_MASK);
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	ocelot_rmw(ocelot,
195062306a36Sopenharmony_ci		   ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(SFIDACCESS_CMD_WRITE),
195162306a36Sopenharmony_ci		   ANA_TABLES_SFIDACCESS_SFID_TBL_CMD_M,
195262306a36Sopenharmony_ci		   ANA_TABLES_SFIDACCESS);
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	return readx_poll_timeout(vsc9959_sfi_access_status, ocelot, val,
195562306a36Sopenharmony_ci				  (!ANA_TABLES_SFIDACCESS_SFID_TBL_CMD(val)),
195662306a36Sopenharmony_ci				  10, 100000);
195762306a36Sopenharmony_ci}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_cistatic int vsc9959_psfp_sfi_list_add(struct ocelot *ocelot,
196062306a36Sopenharmony_ci				     struct felix_stream_filter *sfi,
196162306a36Sopenharmony_ci				     struct list_head *pos)
196262306a36Sopenharmony_ci{
196362306a36Sopenharmony_ci	struct felix_stream_filter *sfi_entry;
196462306a36Sopenharmony_ci	int ret;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	sfi_entry = kmemdup(sfi, sizeof(*sfi_entry), GFP_KERNEL);
196762306a36Sopenharmony_ci	if (!sfi_entry)
196862306a36Sopenharmony_ci		return -ENOMEM;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	refcount_set(&sfi_entry->refcount, 1);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	ret = vsc9959_psfp_sfi_set(ocelot, sfi_entry);
197362306a36Sopenharmony_ci	if (ret) {
197462306a36Sopenharmony_ci		kfree(sfi_entry);
197562306a36Sopenharmony_ci		return ret;
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	vsc9959_psfp_sfidmask_set(ocelot, sfi->index, sfi->portmask);
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	list_add(&sfi_entry->list, pos);
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	return 0;
198362306a36Sopenharmony_ci}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_cistatic int vsc9959_psfp_sfi_table_add(struct ocelot *ocelot,
198662306a36Sopenharmony_ci				      struct felix_stream_filter *sfi)
198762306a36Sopenharmony_ci{
198862306a36Sopenharmony_ci	struct list_head *pos, *q, *last;
198962306a36Sopenharmony_ci	struct felix_stream_filter *tmp;
199062306a36Sopenharmony_ci	struct ocelot_psfp_list *psfp;
199162306a36Sopenharmony_ci	u32 insert = 0;
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	psfp = &ocelot->psfp;
199462306a36Sopenharmony_ci	last = &psfp->sfi_list;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	list_for_each_safe(pos, q, &psfp->sfi_list) {
199762306a36Sopenharmony_ci		tmp = list_entry(pos, struct felix_stream_filter, list);
199862306a36Sopenharmony_ci		if (sfi->sg_valid == tmp->sg_valid &&
199962306a36Sopenharmony_ci		    sfi->fm_valid == tmp->fm_valid &&
200062306a36Sopenharmony_ci		    sfi->portmask == tmp->portmask &&
200162306a36Sopenharmony_ci		    tmp->sgid == sfi->sgid &&
200262306a36Sopenharmony_ci		    tmp->fmid == sfi->fmid) {
200362306a36Sopenharmony_ci			sfi->index = tmp->index;
200462306a36Sopenharmony_ci			refcount_inc(&tmp->refcount);
200562306a36Sopenharmony_ci			return 0;
200662306a36Sopenharmony_ci		}
200762306a36Sopenharmony_ci		/* Make sure that the index is increasing in order. */
200862306a36Sopenharmony_ci		if (tmp->index == insert) {
200962306a36Sopenharmony_ci			last = pos;
201062306a36Sopenharmony_ci			insert++;
201162306a36Sopenharmony_ci		}
201262306a36Sopenharmony_ci	}
201362306a36Sopenharmony_ci	sfi->index = insert;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	return vsc9959_psfp_sfi_list_add(ocelot, sfi, last);
201662306a36Sopenharmony_ci}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_cistatic int vsc9959_psfp_sfi_table_add2(struct ocelot *ocelot,
201962306a36Sopenharmony_ci				       struct felix_stream_filter *sfi,
202062306a36Sopenharmony_ci				       struct felix_stream_filter *sfi2)
202162306a36Sopenharmony_ci{
202262306a36Sopenharmony_ci	struct felix_stream_filter *tmp;
202362306a36Sopenharmony_ci	struct list_head *pos, *q, *last;
202462306a36Sopenharmony_ci	struct ocelot_psfp_list *psfp;
202562306a36Sopenharmony_ci	u32 insert = 0;
202662306a36Sopenharmony_ci	int ret;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	psfp = &ocelot->psfp;
202962306a36Sopenharmony_ci	last = &psfp->sfi_list;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	list_for_each_safe(pos, q, &psfp->sfi_list) {
203262306a36Sopenharmony_ci		tmp = list_entry(pos, struct felix_stream_filter, list);
203362306a36Sopenharmony_ci		/* Make sure that the index is increasing in order. */
203462306a36Sopenharmony_ci		if (tmp->index >= insert + 2)
203562306a36Sopenharmony_ci			break;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci		insert = tmp->index + 1;
203862306a36Sopenharmony_ci		last = pos;
203962306a36Sopenharmony_ci	}
204062306a36Sopenharmony_ci	sfi->index = insert;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	ret = vsc9959_psfp_sfi_list_add(ocelot, sfi, last);
204362306a36Sopenharmony_ci	if (ret)
204462306a36Sopenharmony_ci		return ret;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	sfi2->index = insert + 1;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	return vsc9959_psfp_sfi_list_add(ocelot, sfi2, last->next);
204962306a36Sopenharmony_ci}
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_cistatic struct felix_stream_filter *
205262306a36Sopenharmony_civsc9959_psfp_sfi_table_get(struct list_head *sfi_list, u32 index)
205362306a36Sopenharmony_ci{
205462306a36Sopenharmony_ci	struct felix_stream_filter *tmp;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	list_for_each_entry(tmp, sfi_list, list)
205762306a36Sopenharmony_ci		if (tmp->index == index)
205862306a36Sopenharmony_ci			return tmp;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	return NULL;
206162306a36Sopenharmony_ci}
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_cistatic void vsc9959_psfp_sfi_table_del(struct ocelot *ocelot, u32 index)
206462306a36Sopenharmony_ci{
206562306a36Sopenharmony_ci	struct felix_stream_filter *tmp, *n;
206662306a36Sopenharmony_ci	struct ocelot_psfp_list *psfp;
206762306a36Sopenharmony_ci	u8 z;
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	psfp = &ocelot->psfp;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	list_for_each_entry_safe(tmp, n, &psfp->sfi_list, list)
207262306a36Sopenharmony_ci		if (tmp->index == index) {
207362306a36Sopenharmony_ci			z = refcount_dec_and_test(&tmp->refcount);
207462306a36Sopenharmony_ci			if (z) {
207562306a36Sopenharmony_ci				tmp->enable = 0;
207662306a36Sopenharmony_ci				vsc9959_psfp_sfi_set(ocelot, tmp);
207762306a36Sopenharmony_ci				list_del(&tmp->list);
207862306a36Sopenharmony_ci				kfree(tmp);
207962306a36Sopenharmony_ci			}
208062306a36Sopenharmony_ci			break;
208162306a36Sopenharmony_ci		}
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_cistatic void vsc9959_psfp_parse_gate(const struct flow_action_entry *entry,
208562306a36Sopenharmony_ci				    struct felix_stream_gate *sgi)
208662306a36Sopenharmony_ci{
208762306a36Sopenharmony_ci	sgi->index = entry->hw_index;
208862306a36Sopenharmony_ci	sgi->ipv_valid = (entry->gate.prio < 0) ? 0 : 1;
208962306a36Sopenharmony_ci	sgi->init_ipv = (sgi->ipv_valid) ? entry->gate.prio : 0;
209062306a36Sopenharmony_ci	sgi->basetime = entry->gate.basetime;
209162306a36Sopenharmony_ci	sgi->cycletime = entry->gate.cycletime;
209262306a36Sopenharmony_ci	sgi->num_entries = entry->gate.num_entries;
209362306a36Sopenharmony_ci	sgi->enable = 1;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	memcpy(sgi->entries, entry->gate.entries,
209662306a36Sopenharmony_ci	       entry->gate.num_entries * sizeof(struct action_gate_entry));
209762306a36Sopenharmony_ci}
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_cistatic u32 vsc9959_sgi_cfg_status(struct ocelot *ocelot)
210062306a36Sopenharmony_ci{
210162306a36Sopenharmony_ci	return ocelot_read(ocelot, ANA_SG_ACCESS_CTRL);
210262306a36Sopenharmony_ci}
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_cistatic int vsc9959_psfp_sgi_set(struct ocelot *ocelot,
210562306a36Sopenharmony_ci				struct felix_stream_gate *sgi)
210662306a36Sopenharmony_ci{
210762306a36Sopenharmony_ci	struct action_gate_entry *e;
210862306a36Sopenharmony_ci	struct timespec64 base_ts;
210962306a36Sopenharmony_ci	u32 interval_sum = 0;
211062306a36Sopenharmony_ci	u32 val;
211162306a36Sopenharmony_ci	int i;
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	if (sgi->index > VSC9959_PSFP_GATE_ID_MAX)
211462306a36Sopenharmony_ci		return -EINVAL;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	ocelot_write(ocelot, ANA_SG_ACCESS_CTRL_SGID(sgi->index),
211762306a36Sopenharmony_ci		     ANA_SG_ACCESS_CTRL);
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	if (!sgi->enable) {
212062306a36Sopenharmony_ci		ocelot_rmw(ocelot, ANA_SG_CONFIG_REG_3_INIT_GATE_STATE,
212162306a36Sopenharmony_ci			   ANA_SG_CONFIG_REG_3_INIT_GATE_STATE |
212262306a36Sopenharmony_ci			   ANA_SG_CONFIG_REG_3_GATE_ENABLE,
212362306a36Sopenharmony_ci			   ANA_SG_CONFIG_REG_3);
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci		return 0;
212662306a36Sopenharmony_ci	}
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	if (sgi->cycletime < VSC9959_PSFP_GATE_CYCLETIME_MIN ||
212962306a36Sopenharmony_ci	    sgi->cycletime > NSEC_PER_SEC)
213062306a36Sopenharmony_ci		return -EINVAL;
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	if (sgi->num_entries > VSC9959_PSFP_GATE_LIST_NUM)
213362306a36Sopenharmony_ci		return -EINVAL;
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	vsc9959_new_base_time(ocelot, sgi->basetime, sgi->cycletime, &base_ts);
213662306a36Sopenharmony_ci	ocelot_write(ocelot, base_ts.tv_nsec, ANA_SG_CONFIG_REG_1);
213762306a36Sopenharmony_ci	val = lower_32_bits(base_ts.tv_sec);
213862306a36Sopenharmony_ci	ocelot_write(ocelot, val, ANA_SG_CONFIG_REG_2);
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	val = upper_32_bits(base_ts.tv_sec);
214162306a36Sopenharmony_ci	ocelot_write(ocelot,
214262306a36Sopenharmony_ci		     (sgi->ipv_valid ? ANA_SG_CONFIG_REG_3_IPV_VALID : 0) |
214362306a36Sopenharmony_ci		     ANA_SG_CONFIG_REG_3_INIT_IPV(sgi->init_ipv) |
214462306a36Sopenharmony_ci		     ANA_SG_CONFIG_REG_3_GATE_ENABLE |
214562306a36Sopenharmony_ci		     ANA_SG_CONFIG_REG_3_LIST_LENGTH(sgi->num_entries) |
214662306a36Sopenharmony_ci		     ANA_SG_CONFIG_REG_3_INIT_GATE_STATE |
214762306a36Sopenharmony_ci		     ANA_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB(val),
214862306a36Sopenharmony_ci		     ANA_SG_CONFIG_REG_3);
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	ocelot_write(ocelot, sgi->cycletime, ANA_SG_CONFIG_REG_4);
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	e = sgi->entries;
215362306a36Sopenharmony_ci	for (i = 0; i < sgi->num_entries; i++) {
215462306a36Sopenharmony_ci		u32 ips = (e[i].ipv < 0) ? 0 : (e[i].ipv + 8);
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci		ocelot_write_rix(ocelot, ANA_SG_GCL_GS_CONFIG_IPS(ips) |
215762306a36Sopenharmony_ci				 (e[i].gate_state ?
215862306a36Sopenharmony_ci				  ANA_SG_GCL_GS_CONFIG_GATE_STATE : 0),
215962306a36Sopenharmony_ci				 ANA_SG_GCL_GS_CONFIG, i);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci		interval_sum += e[i].interval;
216262306a36Sopenharmony_ci		ocelot_write_rix(ocelot, interval_sum, ANA_SG_GCL_TI_CONFIG, i);
216362306a36Sopenharmony_ci	}
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	ocelot_rmw(ocelot, ANA_SG_ACCESS_CTRL_CONFIG_CHANGE,
216662306a36Sopenharmony_ci		   ANA_SG_ACCESS_CTRL_CONFIG_CHANGE,
216762306a36Sopenharmony_ci		   ANA_SG_ACCESS_CTRL);
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	return readx_poll_timeout(vsc9959_sgi_cfg_status, ocelot, val,
217062306a36Sopenharmony_ci				  (!(ANA_SG_ACCESS_CTRL_CONFIG_CHANGE & val)),
217162306a36Sopenharmony_ci				  10, 100000);
217262306a36Sopenharmony_ci}
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_cistatic int vsc9959_psfp_sgi_table_add(struct ocelot *ocelot,
217562306a36Sopenharmony_ci				      struct felix_stream_gate *sgi)
217662306a36Sopenharmony_ci{
217762306a36Sopenharmony_ci	struct felix_stream_gate_entry *tmp;
217862306a36Sopenharmony_ci	struct ocelot_psfp_list *psfp;
217962306a36Sopenharmony_ci	int ret;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	psfp = &ocelot->psfp;
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	list_for_each_entry(tmp, &psfp->sgi_list, list)
218462306a36Sopenharmony_ci		if (tmp->index == sgi->index) {
218562306a36Sopenharmony_ci			refcount_inc(&tmp->refcount);
218662306a36Sopenharmony_ci			return 0;
218762306a36Sopenharmony_ci		}
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
219062306a36Sopenharmony_ci	if (!tmp)
219162306a36Sopenharmony_ci		return -ENOMEM;
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	ret = vsc9959_psfp_sgi_set(ocelot, sgi);
219462306a36Sopenharmony_ci	if (ret) {
219562306a36Sopenharmony_ci		kfree(tmp);
219662306a36Sopenharmony_ci		return ret;
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	tmp->index = sgi->index;
220062306a36Sopenharmony_ci	refcount_set(&tmp->refcount, 1);
220162306a36Sopenharmony_ci	list_add_tail(&tmp->list, &psfp->sgi_list);
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	return 0;
220462306a36Sopenharmony_ci}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_cistatic void vsc9959_psfp_sgi_table_del(struct ocelot *ocelot,
220762306a36Sopenharmony_ci				       u32 index)
220862306a36Sopenharmony_ci{
220962306a36Sopenharmony_ci	struct felix_stream_gate_entry *tmp, *n;
221062306a36Sopenharmony_ci	struct felix_stream_gate sgi = {0};
221162306a36Sopenharmony_ci	struct ocelot_psfp_list *psfp;
221262306a36Sopenharmony_ci	u8 z;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	psfp = &ocelot->psfp;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	list_for_each_entry_safe(tmp, n, &psfp->sgi_list, list)
221762306a36Sopenharmony_ci		if (tmp->index == index) {
221862306a36Sopenharmony_ci			z = refcount_dec_and_test(&tmp->refcount);
221962306a36Sopenharmony_ci			if (z) {
222062306a36Sopenharmony_ci				sgi.index = index;
222162306a36Sopenharmony_ci				sgi.enable = 0;
222262306a36Sopenharmony_ci				vsc9959_psfp_sgi_set(ocelot, &sgi);
222362306a36Sopenharmony_ci				list_del(&tmp->list);
222462306a36Sopenharmony_ci				kfree(tmp);
222562306a36Sopenharmony_ci			}
222662306a36Sopenharmony_ci			break;
222762306a36Sopenharmony_ci		}
222862306a36Sopenharmony_ci}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_cistatic int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port,
223162306a36Sopenharmony_ci				   struct flow_cls_offload *f)
223262306a36Sopenharmony_ci{
223362306a36Sopenharmony_ci	struct netlink_ext_ack *extack = f->common.extack;
223462306a36Sopenharmony_ci	struct felix_stream_filter old_sfi, *sfi_entry;
223562306a36Sopenharmony_ci	struct felix_stream_filter sfi = {0};
223662306a36Sopenharmony_ci	const struct flow_action_entry *a;
223762306a36Sopenharmony_ci	struct felix_stream *stream_entry;
223862306a36Sopenharmony_ci	struct felix_stream stream = {0};
223962306a36Sopenharmony_ci	struct felix_stream_gate *sgi;
224062306a36Sopenharmony_ci	struct ocelot_psfp_list *psfp;
224162306a36Sopenharmony_ci	struct ocelot_policer pol;
224262306a36Sopenharmony_ci	int ret, i, size;
224362306a36Sopenharmony_ci	u64 rate, burst;
224462306a36Sopenharmony_ci	u32 index;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	psfp = &ocelot->psfp;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	ret = vsc9959_stream_identify(f, &stream);
224962306a36Sopenharmony_ci	if (ret) {
225062306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Only can match on VID, PCP, and dest MAC");
225162306a36Sopenharmony_ci		return ret;
225262306a36Sopenharmony_ci	}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	mutex_lock(&psfp->lock);
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	flow_action_for_each(i, a, &f->rule->action) {
225762306a36Sopenharmony_ci		switch (a->id) {
225862306a36Sopenharmony_ci		case FLOW_ACTION_GATE:
225962306a36Sopenharmony_ci			size = struct_size(sgi, entries, a->gate.num_entries);
226062306a36Sopenharmony_ci			sgi = kzalloc(size, GFP_KERNEL);
226162306a36Sopenharmony_ci			if (!sgi) {
226262306a36Sopenharmony_ci				ret = -ENOMEM;
226362306a36Sopenharmony_ci				goto err;
226462306a36Sopenharmony_ci			}
226562306a36Sopenharmony_ci			vsc9959_psfp_parse_gate(a, sgi);
226662306a36Sopenharmony_ci			ret = vsc9959_psfp_sgi_table_add(ocelot, sgi);
226762306a36Sopenharmony_ci			if (ret) {
226862306a36Sopenharmony_ci				kfree(sgi);
226962306a36Sopenharmony_ci				goto err;
227062306a36Sopenharmony_ci			}
227162306a36Sopenharmony_ci			sfi.sg_valid = 1;
227262306a36Sopenharmony_ci			sfi.sgid = sgi->index;
227362306a36Sopenharmony_ci			kfree(sgi);
227462306a36Sopenharmony_ci			break;
227562306a36Sopenharmony_ci		case FLOW_ACTION_POLICE:
227662306a36Sopenharmony_ci			index = a->hw_index + VSC9959_PSFP_POLICER_BASE;
227762306a36Sopenharmony_ci			if (index > VSC9959_PSFP_POLICER_MAX) {
227862306a36Sopenharmony_ci				ret = -EINVAL;
227962306a36Sopenharmony_ci				goto err;
228062306a36Sopenharmony_ci			}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci			rate = a->police.rate_bytes_ps;
228362306a36Sopenharmony_ci			burst = rate * PSCHED_NS2TICKS(a->police.burst);
228462306a36Sopenharmony_ci			pol = (struct ocelot_policer) {
228562306a36Sopenharmony_ci				.burst = div_u64(burst, PSCHED_TICKS_PER_SEC),
228662306a36Sopenharmony_ci				.rate = div_u64(rate, 1000) * 8,
228762306a36Sopenharmony_ci			};
228862306a36Sopenharmony_ci			ret = ocelot_vcap_policer_add(ocelot, index, &pol);
228962306a36Sopenharmony_ci			if (ret)
229062306a36Sopenharmony_ci				goto err;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci			sfi.fm_valid = 1;
229362306a36Sopenharmony_ci			sfi.fmid = index;
229462306a36Sopenharmony_ci			sfi.maxsdu = a->police.mtu;
229562306a36Sopenharmony_ci			break;
229662306a36Sopenharmony_ci		default:
229762306a36Sopenharmony_ci			mutex_unlock(&psfp->lock);
229862306a36Sopenharmony_ci			return -EOPNOTSUPP;
229962306a36Sopenharmony_ci		}
230062306a36Sopenharmony_ci	}
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	stream.ports = BIT(port);
230362306a36Sopenharmony_ci	stream.port = port;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	sfi.portmask = stream.ports;
230662306a36Sopenharmony_ci	sfi.prio_valid = (stream.prio < 0 ? 0 : 1);
230762306a36Sopenharmony_ci	sfi.prio = (sfi.prio_valid ? stream.prio : 0);
230862306a36Sopenharmony_ci	sfi.enable = 1;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	/* Check if stream is set. */
231162306a36Sopenharmony_ci	stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &stream);
231262306a36Sopenharmony_ci	if (stream_entry) {
231362306a36Sopenharmony_ci		if (stream_entry->ports & BIT(port)) {
231462306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack,
231562306a36Sopenharmony_ci					   "The stream is added on this port");
231662306a36Sopenharmony_ci			ret = -EEXIST;
231762306a36Sopenharmony_ci			goto err;
231862306a36Sopenharmony_ci		}
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ci		if (stream_entry->ports != BIT(stream_entry->port)) {
232162306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack,
232262306a36Sopenharmony_ci					   "The stream is added on two ports");
232362306a36Sopenharmony_ci			ret = -EEXIST;
232462306a36Sopenharmony_ci			goto err;
232562306a36Sopenharmony_ci		}
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci		stream_entry->ports |= BIT(port);
232862306a36Sopenharmony_ci		stream.ports = stream_entry->ports;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci		sfi_entry = vsc9959_psfp_sfi_table_get(&psfp->sfi_list,
233162306a36Sopenharmony_ci						       stream_entry->sfid);
233262306a36Sopenharmony_ci		memcpy(&old_sfi, sfi_entry, sizeof(old_sfi));
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci		vsc9959_psfp_sfi_table_del(ocelot, stream_entry->sfid);
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci		old_sfi.portmask = stream_entry->ports;
233762306a36Sopenharmony_ci		sfi.portmask = stream.ports;
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci		if (stream_entry->port > port) {
234062306a36Sopenharmony_ci			ret = vsc9959_psfp_sfi_table_add2(ocelot, &sfi,
234162306a36Sopenharmony_ci							  &old_sfi);
234262306a36Sopenharmony_ci			stream_entry->dummy = true;
234362306a36Sopenharmony_ci		} else {
234462306a36Sopenharmony_ci			ret = vsc9959_psfp_sfi_table_add2(ocelot, &old_sfi,
234562306a36Sopenharmony_ci							  &sfi);
234662306a36Sopenharmony_ci			stream.dummy = true;
234762306a36Sopenharmony_ci		}
234862306a36Sopenharmony_ci		if (ret)
234962306a36Sopenharmony_ci			goto err;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci		stream_entry->sfid = old_sfi.index;
235262306a36Sopenharmony_ci	} else {
235362306a36Sopenharmony_ci		ret = vsc9959_psfp_sfi_table_add(ocelot, &sfi);
235462306a36Sopenharmony_ci		if (ret)
235562306a36Sopenharmony_ci			goto err;
235662306a36Sopenharmony_ci	}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	stream.sfid = sfi.index;
235962306a36Sopenharmony_ci	stream.sfid_valid = 1;
236062306a36Sopenharmony_ci	ret = vsc9959_stream_table_add(ocelot, &psfp->stream_list,
236162306a36Sopenharmony_ci				       &stream, extack);
236262306a36Sopenharmony_ci	if (ret) {
236362306a36Sopenharmony_ci		vsc9959_psfp_sfi_table_del(ocelot, stream.sfid);
236462306a36Sopenharmony_ci		goto err;
236562306a36Sopenharmony_ci	}
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	mutex_unlock(&psfp->lock);
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	return 0;
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_cierr:
237262306a36Sopenharmony_ci	if (sfi.sg_valid)
237362306a36Sopenharmony_ci		vsc9959_psfp_sgi_table_del(ocelot, sfi.sgid);
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci	if (sfi.fm_valid)
237662306a36Sopenharmony_ci		ocelot_vcap_policer_del(ocelot, sfi.fmid);
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	mutex_unlock(&psfp->lock);
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	return ret;
238162306a36Sopenharmony_ci}
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_cistatic int vsc9959_psfp_filter_del(struct ocelot *ocelot,
238462306a36Sopenharmony_ci				   struct flow_cls_offload *f)
238562306a36Sopenharmony_ci{
238662306a36Sopenharmony_ci	struct felix_stream *stream, tmp, *stream_entry;
238762306a36Sopenharmony_ci	struct ocelot_psfp_list *psfp = &ocelot->psfp;
238862306a36Sopenharmony_ci	static struct felix_stream_filter *sfi;
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	mutex_lock(&psfp->lock);
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie);
239362306a36Sopenharmony_ci	if (!stream) {
239462306a36Sopenharmony_ci		mutex_unlock(&psfp->lock);
239562306a36Sopenharmony_ci		return -ENOMEM;
239662306a36Sopenharmony_ci	}
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid);
239962306a36Sopenharmony_ci	if (!sfi) {
240062306a36Sopenharmony_ci		mutex_unlock(&psfp->lock);
240162306a36Sopenharmony_ci		return -ENOMEM;
240262306a36Sopenharmony_ci	}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	if (sfi->sg_valid)
240562306a36Sopenharmony_ci		vsc9959_psfp_sgi_table_del(ocelot, sfi->sgid);
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci	if (sfi->fm_valid)
240862306a36Sopenharmony_ci		ocelot_vcap_policer_del(ocelot, sfi->fmid);
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	vsc9959_psfp_sfi_table_del(ocelot, stream->sfid);
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	memcpy(&tmp, stream, sizeof(tmp));
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	stream->sfid_valid = 0;
241562306a36Sopenharmony_ci	vsc9959_stream_table_del(ocelot, stream);
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	stream_entry = vsc9959_stream_table_lookup(&psfp->stream_list, &tmp);
241862306a36Sopenharmony_ci	if (stream_entry) {
241962306a36Sopenharmony_ci		stream_entry->ports = BIT(stream_entry->port);
242062306a36Sopenharmony_ci		if (stream_entry->dummy) {
242162306a36Sopenharmony_ci			stream_entry->dummy = false;
242262306a36Sopenharmony_ci			vsc9959_mact_stream_set(ocelot, stream_entry, NULL);
242362306a36Sopenharmony_ci		}
242462306a36Sopenharmony_ci		vsc9959_psfp_sfidmask_set(ocelot, stream_entry->sfid,
242562306a36Sopenharmony_ci					  stream_entry->ports);
242662306a36Sopenharmony_ci	}
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	mutex_unlock(&psfp->lock);
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	return 0;
243162306a36Sopenharmony_ci}
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_cistatic void vsc9959_update_sfid_stats(struct ocelot *ocelot,
243462306a36Sopenharmony_ci				      struct felix_stream_filter *sfi)
243562306a36Sopenharmony_ci{
243662306a36Sopenharmony_ci	struct felix_stream_filter_counters *s = &sfi->stats;
243762306a36Sopenharmony_ci	u32 match, not_pass_gate, not_pass_sdu, red;
243862306a36Sopenharmony_ci	u32 sfid = sfi->index;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	lockdep_assert_held(&ocelot->stat_view_lock);
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	ocelot_rmw(ocelot, SYS_STAT_CFG_STAT_VIEW(sfid),
244362306a36Sopenharmony_ci		   SYS_STAT_CFG_STAT_VIEW_M,
244462306a36Sopenharmony_ci		   SYS_STAT_CFG);
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	match = ocelot_read(ocelot, SYS_COUNT_SF_MATCHING_FRAMES);
244762306a36Sopenharmony_ci	not_pass_gate = ocelot_read(ocelot, SYS_COUNT_SF_NOT_PASSING_FRAMES);
244862306a36Sopenharmony_ci	not_pass_sdu = ocelot_read(ocelot, SYS_COUNT_SF_NOT_PASSING_SDU);
244962306a36Sopenharmony_ci	red = ocelot_read(ocelot, SYS_COUNT_SF_RED_FRAMES);
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	/* Clear the PSFP counter. */
245262306a36Sopenharmony_ci	ocelot_write(ocelot,
245362306a36Sopenharmony_ci		     SYS_STAT_CFG_STAT_VIEW(sfid) |
245462306a36Sopenharmony_ci		     SYS_STAT_CFG_STAT_CLEAR_SHOT(0x10),
245562306a36Sopenharmony_ci		     SYS_STAT_CFG);
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	s->match += match;
245862306a36Sopenharmony_ci	s->not_pass_gate += not_pass_gate;
245962306a36Sopenharmony_ci	s->not_pass_sdu += not_pass_sdu;
246062306a36Sopenharmony_ci	s->red += red;
246162306a36Sopenharmony_ci}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci/* Caller must hold &ocelot->stat_view_lock */
246462306a36Sopenharmony_cistatic void vsc9959_update_stats(struct ocelot *ocelot)
246562306a36Sopenharmony_ci{
246662306a36Sopenharmony_ci	struct ocelot_psfp_list *psfp = &ocelot->psfp;
246762306a36Sopenharmony_ci	struct felix_stream_filter *sfi;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	mutex_lock(&psfp->lock);
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	list_for_each_entry(sfi, &psfp->sfi_list, list)
247262306a36Sopenharmony_ci		vsc9959_update_sfid_stats(ocelot, sfi);
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	mutex_unlock(&psfp->lock);
247562306a36Sopenharmony_ci}
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_cistatic int vsc9959_psfp_stats_get(struct ocelot *ocelot,
247862306a36Sopenharmony_ci				  struct flow_cls_offload *f,
247962306a36Sopenharmony_ci				  struct flow_stats *stats)
248062306a36Sopenharmony_ci{
248162306a36Sopenharmony_ci	struct ocelot_psfp_list *psfp = &ocelot->psfp;
248262306a36Sopenharmony_ci	struct felix_stream_filter_counters *s;
248362306a36Sopenharmony_ci	static struct felix_stream_filter *sfi;
248462306a36Sopenharmony_ci	struct felix_stream *stream;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	stream = vsc9959_stream_table_get(&psfp->stream_list, f->cookie);
248762306a36Sopenharmony_ci	if (!stream)
248862306a36Sopenharmony_ci		return -ENOMEM;
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	sfi = vsc9959_psfp_sfi_table_get(&psfp->sfi_list, stream->sfid);
249162306a36Sopenharmony_ci	if (!sfi)
249262306a36Sopenharmony_ci		return -EINVAL;
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	mutex_lock(&ocelot->stat_view_lock);
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	vsc9959_update_sfid_stats(ocelot, sfi);
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	s = &sfi->stats;
249962306a36Sopenharmony_ci	stats->pkts = s->match;
250062306a36Sopenharmony_ci	stats->drops = s->not_pass_gate + s->not_pass_sdu + s->red;
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	memset(s, 0, sizeof(*s));
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci	mutex_unlock(&ocelot->stat_view_lock);
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	return 0;
250762306a36Sopenharmony_ci}
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_cistatic void vsc9959_psfp_init(struct ocelot *ocelot)
251062306a36Sopenharmony_ci{
251162306a36Sopenharmony_ci	struct ocelot_psfp_list *psfp = &ocelot->psfp;
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	INIT_LIST_HEAD(&psfp->stream_list);
251462306a36Sopenharmony_ci	INIT_LIST_HEAD(&psfp->sfi_list);
251562306a36Sopenharmony_ci	INIT_LIST_HEAD(&psfp->sgi_list);
251662306a36Sopenharmony_ci	mutex_init(&psfp->lock);
251762306a36Sopenharmony_ci}
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci/* When using cut-through forwarding and the egress port runs at a higher data
252062306a36Sopenharmony_ci * rate than the ingress port, the packet currently under transmission would
252162306a36Sopenharmony_ci * suffer an underrun since it would be transmitted faster than it is received.
252262306a36Sopenharmony_ci * The Felix switch implementation of cut-through forwarding does not check in
252362306a36Sopenharmony_ci * hardware whether this condition is satisfied or not, so we must restrict the
252462306a36Sopenharmony_ci * list of ports that have cut-through forwarding enabled on egress to only be
252562306a36Sopenharmony_ci * the ports operating at the lowest link speed within their respective
252662306a36Sopenharmony_ci * forwarding domain.
252762306a36Sopenharmony_ci */
252862306a36Sopenharmony_cistatic void vsc9959_cut_through_fwd(struct ocelot *ocelot)
252962306a36Sopenharmony_ci{
253062306a36Sopenharmony_ci	struct felix *felix = ocelot_to_felix(ocelot);
253162306a36Sopenharmony_ci	struct dsa_switch *ds = felix->ds;
253262306a36Sopenharmony_ci	int tc, port, other_port;
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	lockdep_assert_held(&ocelot->fwd_domain_lock);
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci	for (port = 0; port < ocelot->num_phys_ports; port++) {
253762306a36Sopenharmony_ci		struct ocelot_port *ocelot_port = ocelot->ports[port];
253862306a36Sopenharmony_ci		struct ocelot_mm_state *mm = &ocelot->mm[port];
253962306a36Sopenharmony_ci		int min_speed = ocelot_port->speed;
254062306a36Sopenharmony_ci		unsigned long mask = 0;
254162306a36Sopenharmony_ci		u32 tmp, val = 0;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci		/* Disable cut-through on ports that are down */
254462306a36Sopenharmony_ci		if (ocelot_port->speed <= 0)
254562306a36Sopenharmony_ci			goto set;
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci		if (dsa_is_cpu_port(ds, port)) {
254862306a36Sopenharmony_ci			/* Ocelot switches forward from the NPI port towards
254962306a36Sopenharmony_ci			 * any port, regardless of it being in the NPI port's
255062306a36Sopenharmony_ci			 * forwarding domain or not.
255162306a36Sopenharmony_ci			 */
255262306a36Sopenharmony_ci			mask = dsa_user_ports(ds);
255362306a36Sopenharmony_ci		} else {
255462306a36Sopenharmony_ci			mask = ocelot_get_bridge_fwd_mask(ocelot, port);
255562306a36Sopenharmony_ci			mask &= ~BIT(port);
255662306a36Sopenharmony_ci			if (ocelot->npi >= 0)
255762306a36Sopenharmony_ci				mask |= BIT(ocelot->npi);
255862306a36Sopenharmony_ci			else
255962306a36Sopenharmony_ci				mask |= ocelot_port_assigned_dsa_8021q_cpu_mask(ocelot,
256062306a36Sopenharmony_ci										port);
256162306a36Sopenharmony_ci		}
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_ci		/* Calculate the minimum link speed, among the ports that are
256462306a36Sopenharmony_ci		 * up, of this source port's forwarding domain.
256562306a36Sopenharmony_ci		 */
256662306a36Sopenharmony_ci		for_each_set_bit(other_port, &mask, ocelot->num_phys_ports) {
256762306a36Sopenharmony_ci			struct ocelot_port *other_ocelot_port;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci			other_ocelot_port = ocelot->ports[other_port];
257062306a36Sopenharmony_ci			if (other_ocelot_port->speed <= 0)
257162306a36Sopenharmony_ci				continue;
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci			if (min_speed > other_ocelot_port->speed)
257462306a36Sopenharmony_ci				min_speed = other_ocelot_port->speed;
257562306a36Sopenharmony_ci		}
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci		/* Enable cut-through forwarding for all traffic classes that
257862306a36Sopenharmony_ci		 * don't have oversized dropping enabled, since this check is
257962306a36Sopenharmony_ci		 * bypassed in cut-through mode. Also exclude preemptible
258062306a36Sopenharmony_ci		 * traffic classes, since these would hang the port for some
258162306a36Sopenharmony_ci		 * reason, if sent as cut-through.
258262306a36Sopenharmony_ci		 */
258362306a36Sopenharmony_ci		if (ocelot_port->speed == min_speed) {
258462306a36Sopenharmony_ci			val = GENMASK(7, 0) & ~mm->active_preemptible_tcs;
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci			for (tc = 0; tc < OCELOT_NUM_TC; tc++)
258762306a36Sopenharmony_ci				if (vsc9959_port_qmaxsdu_get(ocelot, port, tc))
258862306a36Sopenharmony_ci					val &= ~BIT(tc);
258962306a36Sopenharmony_ci		}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ciset:
259262306a36Sopenharmony_ci		tmp = ocelot_read_rix(ocelot, ANA_CUT_THRU_CFG, port);
259362306a36Sopenharmony_ci		if (tmp == val)
259462306a36Sopenharmony_ci			continue;
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci		dev_dbg(ocelot->dev,
259762306a36Sopenharmony_ci			"port %d fwd mask 0x%lx speed %d min_speed %d, %s cut-through forwarding on TC mask 0x%x\n",
259862306a36Sopenharmony_ci			port, mask, ocelot_port->speed, min_speed,
259962306a36Sopenharmony_ci			val ? "enabling" : "disabling", val);
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci		ocelot_write_rix(ocelot, val, ANA_CUT_THRU_CFG, port);
260262306a36Sopenharmony_ci	}
260362306a36Sopenharmony_ci}
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_cistatic const struct ocelot_ops vsc9959_ops = {
260662306a36Sopenharmony_ci	.reset			= vsc9959_reset,
260762306a36Sopenharmony_ci	.wm_enc			= vsc9959_wm_enc,
260862306a36Sopenharmony_ci	.wm_dec			= vsc9959_wm_dec,
260962306a36Sopenharmony_ci	.wm_stat		= vsc9959_wm_stat,
261062306a36Sopenharmony_ci	.port_to_netdev		= felix_port_to_netdev,
261162306a36Sopenharmony_ci	.netdev_to_port		= felix_netdev_to_port,
261262306a36Sopenharmony_ci	.psfp_init		= vsc9959_psfp_init,
261362306a36Sopenharmony_ci	.psfp_filter_add	= vsc9959_psfp_filter_add,
261462306a36Sopenharmony_ci	.psfp_filter_del	= vsc9959_psfp_filter_del,
261562306a36Sopenharmony_ci	.psfp_stats_get		= vsc9959_psfp_stats_get,
261662306a36Sopenharmony_ci	.cut_through_fwd	= vsc9959_cut_through_fwd,
261762306a36Sopenharmony_ci	.tas_clock_adjust	= vsc9959_tas_clock_adjust,
261862306a36Sopenharmony_ci	.update_stats		= vsc9959_update_stats,
261962306a36Sopenharmony_ci	.tas_guard_bands_update	= vsc9959_tas_guard_bands_update,
262062306a36Sopenharmony_ci};
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_cistatic const struct felix_info felix_info_vsc9959 = {
262362306a36Sopenharmony_ci	.resources		= vsc9959_resources,
262462306a36Sopenharmony_ci	.num_resources		= ARRAY_SIZE(vsc9959_resources),
262562306a36Sopenharmony_ci	.resource_names		= vsc9959_resource_names,
262662306a36Sopenharmony_ci	.regfields		= vsc9959_regfields,
262762306a36Sopenharmony_ci	.map			= vsc9959_regmap,
262862306a36Sopenharmony_ci	.ops			= &vsc9959_ops,
262962306a36Sopenharmony_ci	.vcap			= vsc9959_vcap_props,
263062306a36Sopenharmony_ci	.vcap_pol_base		= VSC9959_VCAP_POLICER_BASE,
263162306a36Sopenharmony_ci	.vcap_pol_max		= VSC9959_VCAP_POLICER_MAX,
263262306a36Sopenharmony_ci	.vcap_pol_base2		= 0,
263362306a36Sopenharmony_ci	.vcap_pol_max2		= 0,
263462306a36Sopenharmony_ci	.num_mact_rows		= 2048,
263562306a36Sopenharmony_ci	.num_ports		= VSC9959_NUM_PORTS,
263662306a36Sopenharmony_ci	.num_tx_queues		= OCELOT_NUM_TC,
263762306a36Sopenharmony_ci	.quirks			= FELIX_MAC_QUIRKS,
263862306a36Sopenharmony_ci	.quirk_no_xtr_irq	= true,
263962306a36Sopenharmony_ci	.ptp_caps		= &vsc9959_ptp_caps,
264062306a36Sopenharmony_ci	.mdio_bus_alloc		= vsc9959_mdio_bus_alloc,
264162306a36Sopenharmony_ci	.mdio_bus_free		= vsc9959_mdio_bus_free,
264262306a36Sopenharmony_ci	.port_modes		= vsc9959_port_modes,
264362306a36Sopenharmony_ci	.port_setup_tc		= vsc9959_port_setup_tc,
264462306a36Sopenharmony_ci	.port_sched_speed_set	= vsc9959_sched_speed_set,
264562306a36Sopenharmony_ci};
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci/* The INTB interrupt is shared between for PTP TX timestamp availability
264862306a36Sopenharmony_ci * notification and MAC Merge status change on each port.
264962306a36Sopenharmony_ci */
265062306a36Sopenharmony_cistatic irqreturn_t felix_irq_handler(int irq, void *data)
265162306a36Sopenharmony_ci{
265262306a36Sopenharmony_ci	struct ocelot *ocelot = (struct ocelot *)data;
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci	ocelot_get_txtstamp(ocelot);
265562306a36Sopenharmony_ci	ocelot_mm_irq(ocelot);
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	return IRQ_HANDLED;
265862306a36Sopenharmony_ci}
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_cistatic int felix_pci_probe(struct pci_dev *pdev,
266162306a36Sopenharmony_ci			   const struct pci_device_id *id)
266262306a36Sopenharmony_ci{
266362306a36Sopenharmony_ci	struct dsa_switch *ds;
266462306a36Sopenharmony_ci	struct ocelot *ocelot;
266562306a36Sopenharmony_ci	struct felix *felix;
266662306a36Sopenharmony_ci	int err;
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) {
266962306a36Sopenharmony_ci		dev_info(&pdev->dev, "device is disabled, skipping\n");
267062306a36Sopenharmony_ci		return -ENODEV;
267162306a36Sopenharmony_ci	}
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	err = pci_enable_device(pdev);
267462306a36Sopenharmony_ci	if (err) {
267562306a36Sopenharmony_ci		dev_err(&pdev->dev, "device enable failed\n");
267662306a36Sopenharmony_ci		goto err_pci_enable;
267762306a36Sopenharmony_ci	}
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_ci	felix = kzalloc(sizeof(struct felix), GFP_KERNEL);
268062306a36Sopenharmony_ci	if (!felix) {
268162306a36Sopenharmony_ci		err = -ENOMEM;
268262306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to allocate driver memory\n");
268362306a36Sopenharmony_ci		goto err_alloc_felix;
268462306a36Sopenharmony_ci	}
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	pci_set_drvdata(pdev, felix);
268762306a36Sopenharmony_ci	ocelot = &felix->ocelot;
268862306a36Sopenharmony_ci	ocelot->dev = &pdev->dev;
268962306a36Sopenharmony_ci	ocelot->num_flooding_pgids = OCELOT_NUM_TC;
269062306a36Sopenharmony_ci	felix->info = &felix_info_vsc9959;
269162306a36Sopenharmony_ci	felix->switch_base = pci_resource_start(pdev, VSC9959_SWITCH_PCI_BAR);
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	pci_set_master(pdev);
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL,
269662306a36Sopenharmony_ci					&felix_irq_handler, IRQF_ONESHOT,
269762306a36Sopenharmony_ci					"felix-intb", ocelot);
269862306a36Sopenharmony_ci	if (err) {
269962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to request irq\n");
270062306a36Sopenharmony_ci		goto err_alloc_irq;
270162306a36Sopenharmony_ci	}
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	ocelot->ptp = 1;
270462306a36Sopenharmony_ci	ocelot->mm_supported = true;
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_ci	ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL);
270762306a36Sopenharmony_ci	if (!ds) {
270862306a36Sopenharmony_ci		err = -ENOMEM;
270962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to allocate DSA switch\n");
271062306a36Sopenharmony_ci		goto err_alloc_ds;
271162306a36Sopenharmony_ci	}
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	ds->dev = &pdev->dev;
271462306a36Sopenharmony_ci	ds->num_ports = felix->info->num_ports;
271562306a36Sopenharmony_ci	ds->num_tx_queues = felix->info->num_tx_queues;
271662306a36Sopenharmony_ci	ds->ops = &felix_switch_ops;
271762306a36Sopenharmony_ci	ds->priv = ocelot;
271862306a36Sopenharmony_ci	felix->ds = ds;
271962306a36Sopenharmony_ci	felix->tag_proto = DSA_TAG_PROTO_OCELOT;
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci	err = dsa_register_switch(ds);
272262306a36Sopenharmony_ci	if (err) {
272362306a36Sopenharmony_ci		dev_err_probe(&pdev->dev, err, "Failed to register DSA switch\n");
272462306a36Sopenharmony_ci		goto err_register_ds;
272562306a36Sopenharmony_ci	}
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	return 0;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_cierr_register_ds:
273062306a36Sopenharmony_ci	kfree(ds);
273162306a36Sopenharmony_cierr_alloc_ds:
273262306a36Sopenharmony_cierr_alloc_irq:
273362306a36Sopenharmony_ci	kfree(felix);
273462306a36Sopenharmony_cierr_alloc_felix:
273562306a36Sopenharmony_ci	pci_disable_device(pdev);
273662306a36Sopenharmony_cierr_pci_enable:
273762306a36Sopenharmony_ci	return err;
273862306a36Sopenharmony_ci}
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_cistatic void felix_pci_remove(struct pci_dev *pdev)
274162306a36Sopenharmony_ci{
274262306a36Sopenharmony_ci	struct felix *felix = pci_get_drvdata(pdev);
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	if (!felix)
274562306a36Sopenharmony_ci		return;
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	dsa_unregister_switch(felix->ds);
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	kfree(felix->ds);
275062306a36Sopenharmony_ci	kfree(felix);
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_ci	pci_disable_device(pdev);
275362306a36Sopenharmony_ci}
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_cistatic void felix_pci_shutdown(struct pci_dev *pdev)
275662306a36Sopenharmony_ci{
275762306a36Sopenharmony_ci	struct felix *felix = pci_get_drvdata(pdev);
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci	if (!felix)
276062306a36Sopenharmony_ci		return;
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	dsa_switch_shutdown(felix->ds);
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	pci_set_drvdata(pdev, NULL);
276562306a36Sopenharmony_ci}
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_cistatic struct pci_device_id felix_ids[] = {
276862306a36Sopenharmony_ci	{
276962306a36Sopenharmony_ci		/* NXP LS1028A */
277062306a36Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0),
277162306a36Sopenharmony_ci	},
277262306a36Sopenharmony_ci	{ 0, }
277362306a36Sopenharmony_ci};
277462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, felix_ids);
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_cistatic struct pci_driver felix_vsc9959_pci_driver = {
277762306a36Sopenharmony_ci	.name		= "mscc_felix",
277862306a36Sopenharmony_ci	.id_table	= felix_ids,
277962306a36Sopenharmony_ci	.probe		= felix_pci_probe,
278062306a36Sopenharmony_ci	.remove		= felix_pci_remove,
278162306a36Sopenharmony_ci	.shutdown	= felix_pci_shutdown,
278262306a36Sopenharmony_ci};
278362306a36Sopenharmony_cimodule_pci_driver(felix_vsc9959_pci_driver);
278462306a36Sopenharmony_ci
278562306a36Sopenharmony_ciMODULE_DESCRIPTION("Felix Switch driver");
278662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
2787