2021-08-14 02:53:23

by Colin Foster

[permalink] [raw]
Subject: [RFC PATCH v3 net-next 00/10] add support for VSC75XX control over SPI

Add support for configuration and control of the VSC7511, VSC7512, VSC7513, and
VSC7514 chips over a SPI interface. The intent is to control these chips from an
external CPU. The expectation is to have most of the features of the
net/ethernet/mscc/ocelot_vsc7514 driver.

RFC history:
v1 (accidentally named vN)
Initial architecture. Not functional
General concepts laid out

v2
Near functional. No CPU port communication, but control over all
external ports
Cleaned up regmap implementation from v1

v3
Functional
Shared MDIO transactions routed through mdio-mscc-miim
CPU / NPI port enabled by way of vsc7512_enable_npi_port /
felix->info->enable_npi_port
NPI port tagging functional - Requires a CPU port driver that supports
frames of 1520 bytes. Verified with a patch to the cpsw driver



Colin Foster (10):
net: dsa: ocelot: remove unnecessary pci_bar variables
net: mdio: mscc-miim: convert to a regmap implementation
net: dsa: ocelot: felix: switch to mdio-mscc-miim driver for indirect
mdio access
net: dsa: ocelot: felix: Remove requirement for PCS in felix devices
net: dsa: ocelot: felix: add interface for custom regmaps
net: mscc: ocelot: split register definitions to a separate file
net: mscc: ocelot: expose ocelot wm functions
net: mscc: ocelot: felix: add ability to enable a CPU / NPI port
net: dsa: ocelot: felix: add support for VSC75XX control over SPI
docs: devicetree: add documentation for the VSC7512 SPI device

.../devicetree/bindings/net/dsa/ocelot.txt | 92 ++
drivers/net/dsa/ocelot/Kconfig | 14 +
drivers/net/dsa/ocelot/Makefile | 7 +
drivers/net/dsa/ocelot/felix.c | 11 +-
drivers/net/dsa/ocelot/felix.h | 5 +-
drivers/net/dsa/ocelot/felix_mdio.c | 52 +
drivers/net/dsa/ocelot/felix_mdio.h | 12 +
drivers/net/dsa/ocelot/felix_vsc9959.c | 11 +-
drivers/net/dsa/ocelot/ocelot_vsc7512_spi.c | 1133 +++++++++++++++++
drivers/net/dsa/ocelot/seville_vsc9953.c | 109 +-
drivers/net/ethernet/mscc/Makefile | 2 +
drivers/net/ethernet/mscc/ocelot.c | 8 +
drivers/net/ethernet/mscc/ocelot_regs.c | 309 +++++
drivers/net/ethernet/mscc/ocelot_vsc7514.c | 323 +----
drivers/net/ethernet/mscc/ocelot_wm.c | 39 +
drivers/net/mdio/mdio-mscc-miim.c | 137 +-
include/linux/mdio/mdio-mscc-miim.h | 19 +
include/soc/mscc/ocelot.h | 24 +
include/soc/mscc/ocelot_regs.h | 20 +
19 files changed, 1857 insertions(+), 470 deletions(-)
create mode 100644 drivers/net/dsa/ocelot/felix_mdio.c
create mode 100644 drivers/net/dsa/ocelot/felix_mdio.h
create mode 100644 drivers/net/dsa/ocelot/ocelot_vsc7512_spi.c
create mode 100644 drivers/net/ethernet/mscc/ocelot_regs.c
create mode 100644 drivers/net/ethernet/mscc/ocelot_wm.c
create mode 100644 include/linux/mdio/mdio-mscc-miim.h
create mode 100644 include/soc/mscc/ocelot_regs.h

--
2.25.1


2021-08-14 02:53:28

by Colin Foster

[permalink] [raw]
Subject: [RFC PATCH v3 net-next 06/10] net: mscc: ocelot: split register definitions to a separate file

Moving these to a separate file will allow them to be shared to other
drivers.

Signed-off-by: Colin Foster <[email protected]>
---
drivers/net/ethernet/mscc/Makefile | 1 +
drivers/net/ethernet/mscc/ocelot_regs.c | 309 +++++++++++++++++++++
drivers/net/ethernet/mscc/ocelot_vsc7514.c | 295 +-------------------
include/soc/mscc/ocelot_regs.h | 20 ++
4 files changed, 331 insertions(+), 294 deletions(-)
create mode 100644 drivers/net/ethernet/mscc/ocelot_regs.c
create mode 100644 include/soc/mscc/ocelot_regs.h

diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile
index 722c27694b21..d539a231a478 100644
--- a/drivers/net/ethernet/mscc/Makefile
+++ b/drivers/net/ethernet/mscc/Makefile
@@ -7,6 +7,7 @@ mscc_ocelot_switch_lib-y := \
ocelot_vcap.o \
ocelot_flower.o \
ocelot_ptp.o \
+ ocelot_regs.o \
ocelot_devlink.o
mscc_ocelot_switch_lib-$(CONFIG_BRIDGE_MRP) += ocelot_mrp.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o
diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
new file mode 100644
index 000000000000..b7ba137a7c90
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_regs.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+#include "ocelot.h"
+
+const u32 ocelot_ana_regmap[] = {
+ REG(ANA_ADVLEARN, 0x009000),
+ REG(ANA_VLANMASK, 0x009004),
+ REG(ANA_PORT_B_DOMAIN, 0x009008),
+ REG(ANA_ANAGEFIL, 0x00900c),
+ REG(ANA_ANEVENTS, 0x009010),
+ REG(ANA_STORMLIMIT_BURST, 0x009014),
+ REG(ANA_STORMLIMIT_CFG, 0x009018),
+ REG(ANA_ISOLATED_PORTS, 0x009028),
+ REG(ANA_COMMUNITY_PORTS, 0x00902c),
+ REG(ANA_AUTOAGE, 0x009030),
+ REG(ANA_MACTOPTIONS, 0x009034),
+ REG(ANA_LEARNDISC, 0x009038),
+ REG(ANA_AGENCTRL, 0x00903c),
+ REG(ANA_MIRRORPORTS, 0x009040),
+ REG(ANA_EMIRRORPORTS, 0x009044),
+ REG(ANA_FLOODING, 0x009048),
+ REG(ANA_FLOODING_IPMC, 0x00904c),
+ REG(ANA_SFLOW_CFG, 0x009050),
+ REG(ANA_PORT_MODE, 0x009080),
+ REG(ANA_PGID_PGID, 0x008c00),
+ REG(ANA_TABLES_ANMOVED, 0x008b30),
+ REG(ANA_TABLES_MACHDATA, 0x008b34),
+ REG(ANA_TABLES_MACLDATA, 0x008b38),
+ REG(ANA_TABLES_MACACCESS, 0x008b3c),
+ REG(ANA_TABLES_MACTINDX, 0x008b40),
+ REG(ANA_TABLES_VLANACCESS, 0x008b44),
+ REG(ANA_TABLES_VLANTIDX, 0x008b48),
+ REG(ANA_TABLES_ISDXACCESS, 0x008b4c),
+ REG(ANA_TABLES_ISDXTIDX, 0x008b50),
+ REG(ANA_TABLES_ENTRYLIM, 0x008b00),
+ REG(ANA_TABLES_PTP_ID_HIGH, 0x008b54),
+ REG(ANA_TABLES_PTP_ID_LOW, 0x008b58),
+ REG(ANA_MSTI_STATE, 0x008e00),
+ REG(ANA_PORT_VLAN_CFG, 0x007000),
+ REG(ANA_PORT_DROP_CFG, 0x007004),
+ REG(ANA_PORT_QOS_CFG, 0x007008),
+ REG(ANA_PORT_VCAP_CFG, 0x00700c),
+ REG(ANA_PORT_VCAP_S1_KEY_CFG, 0x007010),
+ REG(ANA_PORT_VCAP_S2_CFG, 0x00701c),
+ REG(ANA_PORT_PCP_DEI_MAP, 0x007020),
+ REG(ANA_PORT_CPU_FWD_CFG, 0x007060),
+ REG(ANA_PORT_CPU_FWD_BPDU_CFG, 0x007064),
+ REG(ANA_PORT_CPU_FWD_GARP_CFG, 0x007068),
+ REG(ANA_PORT_CPU_FWD_CCM_CFG, 0x00706c),
+ REG(ANA_PORT_PORT_CFG, 0x007070),
+ REG(ANA_PORT_POL_CFG, 0x007074),
+ REG(ANA_PORT_PTP_CFG, 0x007078),
+ REG(ANA_PORT_PTP_DLY1_CFG, 0x00707c),
+ REG(ANA_OAM_UPM_LM_CNT, 0x007c00),
+ REG(ANA_PORT_PTP_DLY2_CFG, 0x007080),
+ REG(ANA_PFC_PFC_CFG, 0x008800),
+ REG(ANA_PFC_PFC_TIMER, 0x008804),
+ REG(ANA_IPT_OAM_MEP_CFG, 0x008000),
+ REG(ANA_IPT_IPT, 0x008004),
+ REG(ANA_PPT_PPT, 0x008ac0),
+ REG(ANA_FID_MAP_FID_MAP, 0x000000),
+ REG(ANA_AGGR_CFG, 0x0090b4),
+ REG(ANA_CPUQ_CFG, 0x0090b8),
+ REG(ANA_CPUQ_CFG2, 0x0090bc),
+ REG(ANA_CPUQ_8021_CFG, 0x0090c0),
+ REG(ANA_DSCP_CFG, 0x009100),
+ REG(ANA_DSCP_REWR_CFG, 0x009200),
+ REG(ANA_VCAP_RNG_TYPE_CFG, 0x009240),
+ REG(ANA_VCAP_RNG_VAL_CFG, 0x009260),
+ REG(ANA_VRAP_CFG, 0x009280),
+ REG(ANA_VRAP_HDR_DATA, 0x009284),
+ REG(ANA_VRAP_HDR_MASK, 0x009288),
+ REG(ANA_DISCARD_CFG, 0x00928c),
+ REG(ANA_FID_CFG, 0x009290),
+ REG(ANA_POL_PIR_CFG, 0x004000),
+ REG(ANA_POL_CIR_CFG, 0x004004),
+ REG(ANA_POL_MODE_CFG, 0x004008),
+ REG(ANA_POL_PIR_STATE, 0x00400c),
+ REG(ANA_POL_CIR_STATE, 0x004010),
+ REG(ANA_POL_STATE, 0x004014),
+ REG(ANA_POL_FLOWC, 0x008b80),
+ REG(ANA_POL_HYST, 0x008bec),
+ REG(ANA_POL_MISC_CFG, 0x008bf0),
+};
+EXPORT_SYMBOL(ocelot_ana_regmap);
+
+const u32 ocelot_qs_regmap[] = {
+ REG(QS_XTR_GRP_CFG, 0x000000),
+ REG(QS_XTR_RD, 0x000008),
+ REG(QS_XTR_FRM_PRUNING, 0x000010),
+ REG(QS_XTR_FLUSH, 0x000018),
+ REG(QS_XTR_DATA_PRESENT, 0x00001c),
+ REG(QS_XTR_CFG, 0x000020),
+ REG(QS_INJ_GRP_CFG, 0x000024),
+ REG(QS_INJ_WR, 0x00002c),
+ REG(QS_INJ_CTRL, 0x000034),
+ REG(QS_INJ_STATUS, 0x00003c),
+ REG(QS_INJ_ERR, 0x000040),
+ REG(QS_INH_DBG, 0x000048),
+};
+EXPORT_SYMBOL(ocelot_qs_regmap);
+
+const u32 ocelot_qsys_regmap[] = {
+ REG(QSYS_PORT_MODE, 0x011200),
+ REG(QSYS_SWITCH_PORT_MODE, 0x011234),
+ REG(QSYS_STAT_CNT_CFG, 0x011264),
+ REG(QSYS_EEE_CFG, 0x011268),
+ REG(QSYS_EEE_THRES, 0x011294),
+ REG(QSYS_IGR_NO_SHARING, 0x011298),
+ REG(QSYS_EGR_NO_SHARING, 0x01129c),
+ REG(QSYS_SW_STATUS, 0x0112a0),
+ REG(QSYS_EXT_CPU_CFG, 0x0112d0),
+ REG(QSYS_PAD_CFG, 0x0112d4),
+ REG(QSYS_CPU_GROUP_MAP, 0x0112d8),
+ REG(QSYS_QMAP, 0x0112dc),
+ REG(QSYS_ISDX_SGRP, 0x011400),
+ REG(QSYS_TIMED_FRAME_ENTRY, 0x014000),
+ REG(QSYS_TFRM_MISC, 0x011310),
+ REG(QSYS_TFRM_PORT_DLY, 0x011314),
+ REG(QSYS_TFRM_TIMER_CFG_1, 0x011318),
+ REG(QSYS_TFRM_TIMER_CFG_2, 0x01131c),
+ REG(QSYS_TFRM_TIMER_CFG_3, 0x011320),
+ REG(QSYS_TFRM_TIMER_CFG_4, 0x011324),
+ REG(QSYS_TFRM_TIMER_CFG_5, 0x011328),
+ REG(QSYS_TFRM_TIMER_CFG_6, 0x01132c),
+ REG(QSYS_TFRM_TIMER_CFG_7, 0x011330),
+ REG(QSYS_TFRM_TIMER_CFG_8, 0x011334),
+ REG(QSYS_RED_PROFILE, 0x011338),
+ REG(QSYS_RES_QOS_MODE, 0x011378),
+ REG(QSYS_RES_CFG, 0x012000),
+ REG(QSYS_RES_STAT, 0x012004),
+ REG(QSYS_EGR_DROP_MODE, 0x01137c),
+ REG(QSYS_EQ_CTRL, 0x011380),
+ REG(QSYS_EVENTS_CORE, 0x011384),
+ REG(QSYS_CIR_CFG, 0x000000),
+ REG(QSYS_EIR_CFG, 0x000004),
+ REG(QSYS_SE_CFG, 0x000008),
+ REG(QSYS_SE_DWRR_CFG, 0x00000c),
+ REG(QSYS_SE_CONNECT, 0x00003c),
+ REG(QSYS_SE_DLB_SENSE, 0x000040),
+ REG(QSYS_CIR_STATE, 0x000044),
+ REG(QSYS_EIR_STATE, 0x000048),
+ REG(QSYS_SE_STATE, 0x00004c),
+ REG(QSYS_HSCH_MISC_CFG, 0x011388),
+};
+EXPORT_SYMBOL(ocelot_qsys_regmap);
+
+const u32 ocelot_rew_regmap[] = {
+ REG(REW_PORT_VLAN_CFG, 0x000000),
+ REG(REW_TAG_CFG, 0x000004),
+ REG(REW_PORT_CFG, 0x000008),
+ REG(REW_DSCP_CFG, 0x00000c),
+ REG(REW_PCP_DEI_QOS_MAP_CFG, 0x000010),
+ REG(REW_PTP_CFG, 0x000050),
+ REG(REW_PTP_DLY1_CFG, 0x000054),
+ REG(REW_DSCP_REMAP_DP1_CFG, 0x000690),
+ REG(REW_DSCP_REMAP_CFG, 0x000790),
+ REG(REW_STAT_CFG, 0x000890),
+ REG(REW_PPT, 0x000680),
+};
+EXPORT_SYMBOL(ocelot_rew_regmap);
+
+const u32 ocelot_sys_regmap[] = {
+ REG(SYS_COUNT_RX_OCTETS, 0x000000),
+ REG(SYS_COUNT_RX_UNICAST, 0x000004),
+ REG(SYS_COUNT_RX_MULTICAST, 0x000008),
+ REG(SYS_COUNT_RX_BROADCAST, 0x00000c),
+ REG(SYS_COUNT_RX_SHORTS, 0x000010),
+ REG(SYS_COUNT_RX_FRAGMENTS, 0x000014),
+ REG(SYS_COUNT_RX_JABBERS, 0x000018),
+ REG(SYS_COUNT_RX_CRC_ALIGN_ERRS, 0x00001c),
+ REG(SYS_COUNT_RX_SYM_ERRS, 0x000020),
+ REG(SYS_COUNT_RX_64, 0x000024),
+ REG(SYS_COUNT_RX_65_127, 0x000028),
+ REG(SYS_COUNT_RX_128_255, 0x00002c),
+ REG(SYS_COUNT_RX_256_1023, 0x000030),
+ REG(SYS_COUNT_RX_1024_1526, 0x000034),
+ REG(SYS_COUNT_RX_1527_MAX, 0x000038),
+ REG(SYS_COUNT_RX_PAUSE, 0x00003c),
+ REG(SYS_COUNT_RX_CONTROL, 0x000040),
+ REG(SYS_COUNT_RX_LONGS, 0x000044),
+ REG(SYS_COUNT_RX_CLASSIFIED_DROPS, 0x000048),
+ REG(SYS_COUNT_TX_OCTETS, 0x000100),
+ REG(SYS_COUNT_TX_UNICAST, 0x000104),
+ REG(SYS_COUNT_TX_MULTICAST, 0x000108),
+ REG(SYS_COUNT_TX_BROADCAST, 0x00010c),
+ REG(SYS_COUNT_TX_COLLISION, 0x000110),
+ REG(SYS_COUNT_TX_DROPS, 0x000114),
+ REG(SYS_COUNT_TX_PAUSE, 0x000118),
+ REG(SYS_COUNT_TX_64, 0x00011c),
+ REG(SYS_COUNT_TX_65_127, 0x000120),
+ REG(SYS_COUNT_TX_128_511, 0x000124),
+ REG(SYS_COUNT_TX_512_1023, 0x000128),
+ REG(SYS_COUNT_TX_1024_1526, 0x00012c),
+ REG(SYS_COUNT_TX_1527_MAX, 0x000130),
+ REG(SYS_COUNT_TX_AGING, 0x000170),
+ REG(SYS_RESET_CFG, 0x000508),
+ REG(SYS_CMID, 0x00050c),
+ REG(SYS_VLAN_ETYPE_CFG, 0x000510),
+ REG(SYS_PORT_MODE, 0x000514),
+ REG(SYS_FRONT_PORT_MODE, 0x000548),
+ REG(SYS_FRM_AGING, 0x000574),
+ REG(SYS_STAT_CFG, 0x000578),
+ REG(SYS_SW_STATUS, 0x00057c),
+ REG(SYS_MISC_CFG, 0x0005ac),
+ REG(SYS_REW_MAC_HIGH_CFG, 0x0005b0),
+ REG(SYS_REW_MAC_LOW_CFG, 0x0005dc),
+ REG(SYS_CM_ADDR, 0x000500),
+ REG(SYS_CM_DATA, 0x000504),
+ REG(SYS_PAUSE_CFG, 0x000608),
+ REG(SYS_PAUSE_TOT_CFG, 0x000638),
+ REG(SYS_ATOP, 0x00063c),
+ REG(SYS_ATOP_TOT_CFG, 0x00066c),
+ REG(SYS_MAC_FC_CFG, 0x000670),
+ REG(SYS_MMGT, 0x00069c),
+ REG(SYS_MMGT_FAST, 0x0006a0),
+ REG(SYS_EVENTS_DIF, 0x0006a4),
+ REG(SYS_EVENTS_CORE, 0x0006b4),
+ REG(SYS_CNT, 0x000000),
+ REG(SYS_PTP_STATUS, 0x0006b8),
+ REG(SYS_PTP_TXSTAMP, 0x0006bc),
+ REG(SYS_PTP_NXT, 0x0006c0),
+ REG(SYS_PTP_CFG, 0x0006c4),
+};
+EXPORT_SYMBOL(ocelot_sys_regmap);
+
+const u32 ocelot_vcap_regmap[] = {
+ /* VCAP_CORE_CFG */
+ REG(VCAP_CORE_UPDATE_CTRL, 0x000000),
+ REG(VCAP_CORE_MV_CFG, 0x000004),
+ /* VCAP_CORE_CACHE */
+ REG(VCAP_CACHE_ENTRY_DAT, 0x000008),
+ REG(VCAP_CACHE_MASK_DAT, 0x000108),
+ REG(VCAP_CACHE_ACTION_DAT, 0x000208),
+ REG(VCAP_CACHE_CNT_DAT, 0x000308),
+ REG(VCAP_CACHE_TG_DAT, 0x000388),
+ /* VCAP_CONST */
+ REG(VCAP_CONST_VCAP_VER, 0x000398),
+ REG(VCAP_CONST_ENTRY_WIDTH, 0x00039c),
+ REG(VCAP_CONST_ENTRY_CNT, 0x0003a0),
+ REG(VCAP_CONST_ENTRY_SWCNT, 0x0003a4),
+ REG(VCAP_CONST_ENTRY_TG_WIDTH, 0x0003a8),
+ REG(VCAP_CONST_ACTION_DEF_CNT, 0x0003ac),
+ REG(VCAP_CONST_ACTION_WIDTH, 0x0003b0),
+ REG(VCAP_CONST_CNT_WIDTH, 0x0003b4),
+ REG(VCAP_CONST_CORE_CNT, 0x0003b8),
+ REG(VCAP_CONST_IF_CNT, 0x0003bc),
+};
+EXPORT_SYMBOL(ocelot_vcap_regmap);
+
+const u32 ocelot_ptp_regmap[] = {
+ REG(PTP_PIN_CFG, 0x000000),
+ REG(PTP_PIN_TOD_SEC_MSB, 0x000004),
+ REG(PTP_PIN_TOD_SEC_LSB, 0x000008),
+ REG(PTP_PIN_TOD_NSEC, 0x00000c),
+ REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014),
+ REG(PTP_PIN_WF_LOW_PERIOD, 0x000018),
+ REG(PTP_CFG_MISC, 0x0000a0),
+ REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4),
+ REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8),
+};
+EXPORT_SYMBOL(ocelot_ptp_regmap);
+
+const u32 ocelot_dev_gmii_regmap[] = {
+ REG(DEV_CLOCK_CFG, 0x0),
+ REG(DEV_PORT_MISC, 0x4),
+ REG(DEV_EVENTS, 0x8),
+ REG(DEV_EEE_CFG, 0xc),
+ REG(DEV_RX_PATH_DELAY, 0x10),
+ REG(DEV_TX_PATH_DELAY, 0x14),
+ REG(DEV_PTP_PREDICT_CFG, 0x18),
+ REG(DEV_MAC_ENA_CFG, 0x1c),
+ REG(DEV_MAC_MODE_CFG, 0x20),
+ REG(DEV_MAC_MAXLEN_CFG, 0x24),
+ REG(DEV_MAC_TAGS_CFG, 0x28),
+ REG(DEV_MAC_ADV_CHK_CFG, 0x2c),
+ REG(DEV_MAC_IFG_CFG, 0x30),
+ REG(DEV_MAC_HDX_CFG, 0x34),
+ REG(DEV_MAC_DBG_CFG, 0x38),
+ REG(DEV_MAC_FC_MAC_LOW_CFG, 0x3c),
+ REG(DEV_MAC_FC_MAC_HIGH_CFG, 0x40),
+ REG(DEV_MAC_STICKY, 0x44),
+ REG(PCS1G_CFG, 0x48),
+ REG(PCS1G_MODE_CFG, 0x4c),
+ REG(PCS1G_SD_CFG, 0x50),
+ REG(PCS1G_ANEG_CFG, 0x54),
+ REG(PCS1G_ANEG_NP_CFG, 0x58),
+ REG(PCS1G_LB_CFG, 0x5c),
+ REG(PCS1G_DBG_CFG, 0x60),
+ REG(PCS1G_CDET_CFG, 0x64),
+ REG(PCS1G_ANEG_STATUS, 0x68),
+ REG(PCS1G_ANEG_NP_STATUS, 0x6c),
+ REG(PCS1G_LINK_STATUS, 0x70),
+ REG(PCS1G_LINK_DOWN_CNT, 0x74),
+ REG(PCS1G_STICKY, 0x78),
+ REG(PCS1G_DEBUG_STATUS, 0x7c),
+ REG(PCS1G_LPI_CFG, 0x80),
+ REG(PCS1G_LPI_WAKE_ERROR_CNT, 0x84),
+ REG(PCS1G_LPI_STATUS, 0x88),
+ REG(PCS1G_TSTPAT_MODE_CFG, 0x8c),
+ REG(PCS1G_TSTPAT_STATUS, 0x90),
+ REG(DEV_PCS_FX100_CFG, 0x94),
+ REG(DEV_PCS_FX100_STATUS, 0x98),
+};
+EXPORT_SYMBOL(ocelot_dev_gmii_regmap);
diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
index 4bd7e9d9ec61..ef1bf24f51b5 100644
--- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c
+++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
@@ -16,303 +16,10 @@
#include <net/switchdev.h>

#include <soc/mscc/ocelot_vcap.h>
+#include <soc/mscc/ocelot_regs.h>
#include <soc/mscc/ocelot_hsio.h>
#include "ocelot.h"

-static const u32 ocelot_ana_regmap[] = {
- REG(ANA_ADVLEARN, 0x009000),
- REG(ANA_VLANMASK, 0x009004),
- REG(ANA_PORT_B_DOMAIN, 0x009008),
- REG(ANA_ANAGEFIL, 0x00900c),
- REG(ANA_ANEVENTS, 0x009010),
- REG(ANA_STORMLIMIT_BURST, 0x009014),
- REG(ANA_STORMLIMIT_CFG, 0x009018),
- REG(ANA_ISOLATED_PORTS, 0x009028),
- REG(ANA_COMMUNITY_PORTS, 0x00902c),
- REG(ANA_AUTOAGE, 0x009030),
- REG(ANA_MACTOPTIONS, 0x009034),
- REG(ANA_LEARNDISC, 0x009038),
- REG(ANA_AGENCTRL, 0x00903c),
- REG(ANA_MIRRORPORTS, 0x009040),
- REG(ANA_EMIRRORPORTS, 0x009044),
- REG(ANA_FLOODING, 0x009048),
- REG(ANA_FLOODING_IPMC, 0x00904c),
- REG(ANA_SFLOW_CFG, 0x009050),
- REG(ANA_PORT_MODE, 0x009080),
- REG(ANA_PGID_PGID, 0x008c00),
- REG(ANA_TABLES_ANMOVED, 0x008b30),
- REG(ANA_TABLES_MACHDATA, 0x008b34),
- REG(ANA_TABLES_MACLDATA, 0x008b38),
- REG(ANA_TABLES_MACACCESS, 0x008b3c),
- REG(ANA_TABLES_MACTINDX, 0x008b40),
- REG(ANA_TABLES_VLANACCESS, 0x008b44),
- REG(ANA_TABLES_VLANTIDX, 0x008b48),
- REG(ANA_TABLES_ISDXACCESS, 0x008b4c),
- REG(ANA_TABLES_ISDXTIDX, 0x008b50),
- REG(ANA_TABLES_ENTRYLIM, 0x008b00),
- REG(ANA_TABLES_PTP_ID_HIGH, 0x008b54),
- REG(ANA_TABLES_PTP_ID_LOW, 0x008b58),
- REG(ANA_MSTI_STATE, 0x008e00),
- REG(ANA_PORT_VLAN_CFG, 0x007000),
- REG(ANA_PORT_DROP_CFG, 0x007004),
- REG(ANA_PORT_QOS_CFG, 0x007008),
- REG(ANA_PORT_VCAP_CFG, 0x00700c),
- REG(ANA_PORT_VCAP_S1_KEY_CFG, 0x007010),
- REG(ANA_PORT_VCAP_S2_CFG, 0x00701c),
- REG(ANA_PORT_PCP_DEI_MAP, 0x007020),
- REG(ANA_PORT_CPU_FWD_CFG, 0x007060),
- REG(ANA_PORT_CPU_FWD_BPDU_CFG, 0x007064),
- REG(ANA_PORT_CPU_FWD_GARP_CFG, 0x007068),
- REG(ANA_PORT_CPU_FWD_CCM_CFG, 0x00706c),
- REG(ANA_PORT_PORT_CFG, 0x007070),
- REG(ANA_PORT_POL_CFG, 0x007074),
- REG(ANA_PORT_PTP_CFG, 0x007078),
- REG(ANA_PORT_PTP_DLY1_CFG, 0x00707c),
- REG(ANA_OAM_UPM_LM_CNT, 0x007c00),
- REG(ANA_PORT_PTP_DLY2_CFG, 0x007080),
- REG(ANA_PFC_PFC_CFG, 0x008800),
- REG(ANA_PFC_PFC_TIMER, 0x008804),
- REG(ANA_IPT_OAM_MEP_CFG, 0x008000),
- REG(ANA_IPT_IPT, 0x008004),
- REG(ANA_PPT_PPT, 0x008ac0),
- REG(ANA_FID_MAP_FID_MAP, 0x000000),
- REG(ANA_AGGR_CFG, 0x0090b4),
- REG(ANA_CPUQ_CFG, 0x0090b8),
- REG(ANA_CPUQ_CFG2, 0x0090bc),
- REG(ANA_CPUQ_8021_CFG, 0x0090c0),
- REG(ANA_DSCP_CFG, 0x009100),
- REG(ANA_DSCP_REWR_CFG, 0x009200),
- REG(ANA_VCAP_RNG_TYPE_CFG, 0x009240),
- REG(ANA_VCAP_RNG_VAL_CFG, 0x009260),
- REG(ANA_VRAP_CFG, 0x009280),
- REG(ANA_VRAP_HDR_DATA, 0x009284),
- REG(ANA_VRAP_HDR_MASK, 0x009288),
- REG(ANA_DISCARD_CFG, 0x00928c),
- REG(ANA_FID_CFG, 0x009290),
- REG(ANA_POL_PIR_CFG, 0x004000),
- REG(ANA_POL_CIR_CFG, 0x004004),
- REG(ANA_POL_MODE_CFG, 0x004008),
- REG(ANA_POL_PIR_STATE, 0x00400c),
- REG(ANA_POL_CIR_STATE, 0x004010),
- REG(ANA_POL_STATE, 0x004014),
- REG(ANA_POL_FLOWC, 0x008b80),
- REG(ANA_POL_HYST, 0x008bec),
- REG(ANA_POL_MISC_CFG, 0x008bf0),
-};
-
-static const u32 ocelot_qs_regmap[] = {
- REG(QS_XTR_GRP_CFG, 0x000000),
- REG(QS_XTR_RD, 0x000008),
- REG(QS_XTR_FRM_PRUNING, 0x000010),
- REG(QS_XTR_FLUSH, 0x000018),
- REG(QS_XTR_DATA_PRESENT, 0x00001c),
- REG(QS_XTR_CFG, 0x000020),
- REG(QS_INJ_GRP_CFG, 0x000024),
- REG(QS_INJ_WR, 0x00002c),
- REG(QS_INJ_CTRL, 0x000034),
- REG(QS_INJ_STATUS, 0x00003c),
- REG(QS_INJ_ERR, 0x000040),
- REG(QS_INH_DBG, 0x000048),
-};
-
-static const u32 ocelot_qsys_regmap[] = {
- REG(QSYS_PORT_MODE, 0x011200),
- REG(QSYS_SWITCH_PORT_MODE, 0x011234),
- REG(QSYS_STAT_CNT_CFG, 0x011264),
- REG(QSYS_EEE_CFG, 0x011268),
- REG(QSYS_EEE_THRES, 0x011294),
- REG(QSYS_IGR_NO_SHARING, 0x011298),
- REG(QSYS_EGR_NO_SHARING, 0x01129c),
- REG(QSYS_SW_STATUS, 0x0112a0),
- REG(QSYS_EXT_CPU_CFG, 0x0112d0),
- REG(QSYS_PAD_CFG, 0x0112d4),
- REG(QSYS_CPU_GROUP_MAP, 0x0112d8),
- REG(QSYS_QMAP, 0x0112dc),
- REG(QSYS_ISDX_SGRP, 0x011400),
- REG(QSYS_TIMED_FRAME_ENTRY, 0x014000),
- REG(QSYS_TFRM_MISC, 0x011310),
- REG(QSYS_TFRM_PORT_DLY, 0x011314),
- REG(QSYS_TFRM_TIMER_CFG_1, 0x011318),
- REG(QSYS_TFRM_TIMER_CFG_2, 0x01131c),
- REG(QSYS_TFRM_TIMER_CFG_3, 0x011320),
- REG(QSYS_TFRM_TIMER_CFG_4, 0x011324),
- REG(QSYS_TFRM_TIMER_CFG_5, 0x011328),
- REG(QSYS_TFRM_TIMER_CFG_6, 0x01132c),
- REG(QSYS_TFRM_TIMER_CFG_7, 0x011330),
- REG(QSYS_TFRM_TIMER_CFG_8, 0x011334),
- REG(QSYS_RED_PROFILE, 0x011338),
- REG(QSYS_RES_QOS_MODE, 0x011378),
- REG(QSYS_RES_CFG, 0x012000),
- REG(QSYS_RES_STAT, 0x012004),
- REG(QSYS_EGR_DROP_MODE, 0x01137c),
- REG(QSYS_EQ_CTRL, 0x011380),
- REG(QSYS_EVENTS_CORE, 0x011384),
- REG(QSYS_CIR_CFG, 0x000000),
- REG(QSYS_EIR_CFG, 0x000004),
- REG(QSYS_SE_CFG, 0x000008),
- REG(QSYS_SE_DWRR_CFG, 0x00000c),
- REG(QSYS_SE_CONNECT, 0x00003c),
- REG(QSYS_SE_DLB_SENSE, 0x000040),
- REG(QSYS_CIR_STATE, 0x000044),
- REG(QSYS_EIR_STATE, 0x000048),
- REG(QSYS_SE_STATE, 0x00004c),
- REG(QSYS_HSCH_MISC_CFG, 0x011388),
-};
-
-static const u32 ocelot_rew_regmap[] = {
- REG(REW_PORT_VLAN_CFG, 0x000000),
- REG(REW_TAG_CFG, 0x000004),
- REG(REW_PORT_CFG, 0x000008),
- REG(REW_DSCP_CFG, 0x00000c),
- REG(REW_PCP_DEI_QOS_MAP_CFG, 0x000010),
- REG(REW_PTP_CFG, 0x000050),
- REG(REW_PTP_DLY1_CFG, 0x000054),
- REG(REW_DSCP_REMAP_DP1_CFG, 0x000690),
- REG(REW_DSCP_REMAP_CFG, 0x000790),
- REG(REW_STAT_CFG, 0x000890),
- REG(REW_PPT, 0x000680),
-};
-
-static const u32 ocelot_sys_regmap[] = {
- REG(SYS_COUNT_RX_OCTETS, 0x000000),
- REG(SYS_COUNT_RX_UNICAST, 0x000004),
- REG(SYS_COUNT_RX_MULTICAST, 0x000008),
- REG(SYS_COUNT_RX_BROADCAST, 0x00000c),
- REG(SYS_COUNT_RX_SHORTS, 0x000010),
- REG(SYS_COUNT_RX_FRAGMENTS, 0x000014),
- REG(SYS_COUNT_RX_JABBERS, 0x000018),
- REG(SYS_COUNT_RX_CRC_ALIGN_ERRS, 0x00001c),
- REG(SYS_COUNT_RX_SYM_ERRS, 0x000020),
- REG(SYS_COUNT_RX_64, 0x000024),
- REG(SYS_COUNT_RX_65_127, 0x000028),
- REG(SYS_COUNT_RX_128_255, 0x00002c),
- REG(SYS_COUNT_RX_256_1023, 0x000030),
- REG(SYS_COUNT_RX_1024_1526, 0x000034),
- REG(SYS_COUNT_RX_1527_MAX, 0x000038),
- REG(SYS_COUNT_RX_PAUSE, 0x00003c),
- REG(SYS_COUNT_RX_CONTROL, 0x000040),
- REG(SYS_COUNT_RX_LONGS, 0x000044),
- REG(SYS_COUNT_RX_CLASSIFIED_DROPS, 0x000048),
- REG(SYS_COUNT_TX_OCTETS, 0x000100),
- REG(SYS_COUNT_TX_UNICAST, 0x000104),
- REG(SYS_COUNT_TX_MULTICAST, 0x000108),
- REG(SYS_COUNT_TX_BROADCAST, 0x00010c),
- REG(SYS_COUNT_TX_COLLISION, 0x000110),
- REG(SYS_COUNT_TX_DROPS, 0x000114),
- REG(SYS_COUNT_TX_PAUSE, 0x000118),
- REG(SYS_COUNT_TX_64, 0x00011c),
- REG(SYS_COUNT_TX_65_127, 0x000120),
- REG(SYS_COUNT_TX_128_511, 0x000124),
- REG(SYS_COUNT_TX_512_1023, 0x000128),
- REG(SYS_COUNT_TX_1024_1526, 0x00012c),
- REG(SYS_COUNT_TX_1527_MAX, 0x000130),
- REG(SYS_COUNT_TX_AGING, 0x000170),
- REG(SYS_RESET_CFG, 0x000508),
- REG(SYS_CMID, 0x00050c),
- REG(SYS_VLAN_ETYPE_CFG, 0x000510),
- REG(SYS_PORT_MODE, 0x000514),
- REG(SYS_FRONT_PORT_MODE, 0x000548),
- REG(SYS_FRM_AGING, 0x000574),
- REG(SYS_STAT_CFG, 0x000578),
- REG(SYS_SW_STATUS, 0x00057c),
- REG(SYS_MISC_CFG, 0x0005ac),
- REG(SYS_REW_MAC_HIGH_CFG, 0x0005b0),
- REG(SYS_REW_MAC_LOW_CFG, 0x0005dc),
- REG(SYS_CM_ADDR, 0x000500),
- REG(SYS_CM_DATA, 0x000504),
- REG(SYS_PAUSE_CFG, 0x000608),
- REG(SYS_PAUSE_TOT_CFG, 0x000638),
- REG(SYS_ATOP, 0x00063c),
- REG(SYS_ATOP_TOT_CFG, 0x00066c),
- REG(SYS_MAC_FC_CFG, 0x000670),
- REG(SYS_MMGT, 0x00069c),
- REG(SYS_MMGT_FAST, 0x0006a0),
- REG(SYS_EVENTS_DIF, 0x0006a4),
- REG(SYS_EVENTS_CORE, 0x0006b4),
- REG(SYS_CNT, 0x000000),
- REG(SYS_PTP_STATUS, 0x0006b8),
- REG(SYS_PTP_TXSTAMP, 0x0006bc),
- REG(SYS_PTP_NXT, 0x0006c0),
- REG(SYS_PTP_CFG, 0x0006c4),
-};
-
-static const u32 ocelot_vcap_regmap[] = {
- /* VCAP_CORE_CFG */
- REG(VCAP_CORE_UPDATE_CTRL, 0x000000),
- REG(VCAP_CORE_MV_CFG, 0x000004),
- /* VCAP_CORE_CACHE */
- REG(VCAP_CACHE_ENTRY_DAT, 0x000008),
- REG(VCAP_CACHE_MASK_DAT, 0x000108),
- REG(VCAP_CACHE_ACTION_DAT, 0x000208),
- REG(VCAP_CACHE_CNT_DAT, 0x000308),
- REG(VCAP_CACHE_TG_DAT, 0x000388),
- /* VCAP_CONST */
- REG(VCAP_CONST_VCAP_VER, 0x000398),
- REG(VCAP_CONST_ENTRY_WIDTH, 0x00039c),
- REG(VCAP_CONST_ENTRY_CNT, 0x0003a0),
- REG(VCAP_CONST_ENTRY_SWCNT, 0x0003a4),
- REG(VCAP_CONST_ENTRY_TG_WIDTH, 0x0003a8),
- REG(VCAP_CONST_ACTION_DEF_CNT, 0x0003ac),
- REG(VCAP_CONST_ACTION_WIDTH, 0x0003b0),
- REG(VCAP_CONST_CNT_WIDTH, 0x0003b4),
- REG(VCAP_CONST_CORE_CNT, 0x0003b8),
- REG(VCAP_CONST_IF_CNT, 0x0003bc),
-};
-
-static const u32 ocelot_ptp_regmap[] = {
- REG(PTP_PIN_CFG, 0x000000),
- REG(PTP_PIN_TOD_SEC_MSB, 0x000004),
- REG(PTP_PIN_TOD_SEC_LSB, 0x000008),
- REG(PTP_PIN_TOD_NSEC, 0x00000c),
- REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014),
- REG(PTP_PIN_WF_LOW_PERIOD, 0x000018),
- REG(PTP_CFG_MISC, 0x0000a0),
- REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4),
- REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8),
-};
-
-static const u32 ocelot_dev_gmii_regmap[] = {
- REG(DEV_CLOCK_CFG, 0x0),
- REG(DEV_PORT_MISC, 0x4),
- REG(DEV_EVENTS, 0x8),
- REG(DEV_EEE_CFG, 0xc),
- REG(DEV_RX_PATH_DELAY, 0x10),
- REG(DEV_TX_PATH_DELAY, 0x14),
- REG(DEV_PTP_PREDICT_CFG, 0x18),
- REG(DEV_MAC_ENA_CFG, 0x1c),
- REG(DEV_MAC_MODE_CFG, 0x20),
- REG(DEV_MAC_MAXLEN_CFG, 0x24),
- REG(DEV_MAC_TAGS_CFG, 0x28),
- REG(DEV_MAC_ADV_CHK_CFG, 0x2c),
- REG(DEV_MAC_IFG_CFG, 0x30),
- REG(DEV_MAC_HDX_CFG, 0x34),
- REG(DEV_MAC_DBG_CFG, 0x38),
- REG(DEV_MAC_FC_MAC_LOW_CFG, 0x3c),
- REG(DEV_MAC_FC_MAC_HIGH_CFG, 0x40),
- REG(DEV_MAC_STICKY, 0x44),
- REG(PCS1G_CFG, 0x48),
- REG(PCS1G_MODE_CFG, 0x4c),
- REG(PCS1G_SD_CFG, 0x50),
- REG(PCS1G_ANEG_CFG, 0x54),
- REG(PCS1G_ANEG_NP_CFG, 0x58),
- REG(PCS1G_LB_CFG, 0x5c),
- REG(PCS1G_DBG_CFG, 0x60),
- REG(PCS1G_CDET_CFG, 0x64),
- REG(PCS1G_ANEG_STATUS, 0x68),
- REG(PCS1G_ANEG_NP_STATUS, 0x6c),
- REG(PCS1G_LINK_STATUS, 0x70),
- REG(PCS1G_LINK_DOWN_CNT, 0x74),
- REG(PCS1G_STICKY, 0x78),
- REG(PCS1G_DEBUG_STATUS, 0x7c),
- REG(PCS1G_LPI_CFG, 0x80),
- REG(PCS1G_LPI_WAKE_ERROR_CNT, 0x84),
- REG(PCS1G_LPI_STATUS, 0x88),
- REG(PCS1G_TSTPAT_MODE_CFG, 0x8c),
- REG(PCS1G_TSTPAT_STATUS, 0x90),
- REG(DEV_PCS_FX100_CFG, 0x94),
- REG(DEV_PCS_FX100_STATUS, 0x98),
-};
-
static const u32 *ocelot_regmap[TARGET_MAX] = {
[ANA] = ocelot_ana_regmap,
[QS] = ocelot_qs_regmap,
diff --git a/include/soc/mscc/ocelot_regs.h b/include/soc/mscc/ocelot_regs.h
new file mode 100644
index 000000000000..d4508eb9e04a
--- /dev/null
+++ b/include/soc/mscc/ocelot_regs.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2021 Innovative Advantage Inc.
+ */
+
+#ifndef OCELOT_REGS_H
+#define OCELOT_REGS_H
+
+extern const u32 ocelot_ana_regmap[];
+extern const u32 ocelot_qs_regmap[];
+extern const u32 ocelot_qsys_regmap[];
+extern const u32 ocelot_rew_regmap[];
+extern const u32 ocelot_sys_regmap[];
+extern const u32 ocelot_vcap_regmap[];
+extern const u32 ocelot_ptp_regmap[];
+extern const u32 ocelot_dev_gmii_regmap[];
+
+#endif
--
2.25.1

2021-08-14 02:54:00

by Colin Foster

[permalink] [raw]
Subject: [RFC PATCH v3 net-next 09/10] net: dsa: ocelot: felix: add support for VSC75XX control over SPI

Utilize the Felix and Ocelot drivers to allow control of the VSC7511,
VSC7512, VSC7513 and VSC7514 chips from an external CPU over SPI.

Signed-off-by: Colin Foster <[email protected]>
---
drivers/net/dsa/ocelot/Kconfig | 13 +
drivers/net/dsa/ocelot/Makefile | 6 +
drivers/net/dsa/ocelot/ocelot_vsc7512_spi.c | 1133 +++++++++++++++++++
drivers/net/ethernet/mscc/ocelot.c | 8 +
include/soc/mscc/ocelot.h | 19 +
5 files changed, 1179 insertions(+)
create mode 100644 drivers/net/dsa/ocelot/ocelot_vsc7512_spi.c

diff --git a/drivers/net/dsa/ocelot/Kconfig b/drivers/net/dsa/ocelot/Kconfig
index 61bcc88ae4c1..bd7354b4187f 100644
--- a/drivers/net/dsa/ocelot/Kconfig
+++ b/drivers/net/dsa/ocelot/Kconfig
@@ -14,6 +14,19 @@ config NET_DSA_MSCC_FELIX
This driver supports the VSC9959 (Felix) switch, which is embedded as
a PCIe function of the NXP LS1028A ENETC RCiEP.

+config NET_DSA_MSCC_OCELOT_SPI
+ tristate "Ocelot Ethernet SPI switch support"
+ depends on NET_DSA && SPI
+ depends on NET_VENDOR_MICROSEMI
+ select MDIO_MSCC_MIIM
+ select MSCC_OCELOT_SWITCH_LIB
+ select NET_DSA_TAG_OCELOT_8021Q
+ select NET_DSA_TAG_OCELOT
+ help
+ This driver supports the VSC7511, VSC7512, VSC7513 and VSC7514 chips
+ when controlled through SPI. It can be used with the Microsemi dev
+ boards and an external CPU or custom hardware.
+
config NET_DSA_MSCC_SEVILLE
tristate "Ocelot / Seville Ethernet switch support"
depends on NET_DSA
diff --git a/drivers/net/dsa/ocelot/Makefile b/drivers/net/dsa/ocelot/Makefile
index 34b9b128efb8..6ccd5482de7b 100644
--- a/drivers/net/dsa/ocelot/Makefile
+++ b/drivers/net/dsa/ocelot/Makefile
@@ -1,11 +1,17 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o
+obj-$(CONFIG_NET_DSA_MSCC_OCELOT_SPI) += mscc_ocelot_spi.o
obj-$(CONFIG_NET_DSA_MSCC_SEVILLE) += mscc_seville.o

mscc_felix-objs := \
felix.o \
felix_vsc9959.o

+mscc_ocelot_spi-objs := \
+ felix.o \
+ felix_mdio.o \
+ ocelot_vsc7512_spi.o
+
mscc_seville-objs := \
felix.o \
felix_mdio.o \
diff --git a/drivers/net/dsa/ocelot/ocelot_vsc7512_spi.c b/drivers/net/dsa/ocelot/ocelot_vsc7512_spi.c
new file mode 100644
index 000000000000..51c9f17960ec
--- /dev/null
+++ b/drivers/net/dsa/ocelot/ocelot_vsc7512_spi.c
@@ -0,0 +1,1133 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Copyright 2017 Microsemi Corporation
+ * Copyright 2018-2019 NXP Semiconductors
+ * Copyright 2021 Innovative Advantage Inc.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/spi/spi.h>
+#include <linux/iopoll.h>
+#include <linux/kconfig.h>
+#include <linux/mdio.h>
+#include <linux/regmap.h>
+#include <soc/mscc/ocelot_ana.h>
+#include <soc/mscc/ocelot_dev.h>
+#include <soc/mscc/ocelot_qsys.h>
+#include <soc/mscc/ocelot_vcap.h>
+#include <soc/mscc/ocelot_ptp.h>
+#include <soc/mscc/ocelot_regs.h>
+#include <soc/mscc/ocelot_sys.h>
+#include <soc/mscc/ocelot.h>
+#include "felix.h"
+#include "felix_mdio.h"
+
+struct ocelot_spi_data {
+ int spi_padding_bytes;
+ struct felix felix;
+ struct spi_device *spi;
+};
+
+static const u32 vsc7512_dev_cpuorg_regmap[] = {
+ REG(DEV_CPUORG_IF_CTRL, 0x0000),
+ REG(DEV_CPUORG_IF_CFGSTAT, 0x0004),
+ REG(DEV_CPUORG_ORG_CFG, 0x0008),
+ REG(DEV_CPUORG_ERR_CNTS, 0x000c),
+ REG(DEV_CPUORG_TIMEOUT_CFG, 0x0010),
+ REG(DEV_CPUORG_GPR, 0x0014),
+ REG(DEV_CPUORG_MAILBOX_SET, 0x0018),
+ REG(DEV_CPUORG_MAILBOX_CLR, 0x001c),
+ REG(DEV_CPUORG_MAILBOX, 0x0020),
+ REG(DEV_CPUORG_SEMA_CFG, 0x0024),
+ REG(DEV_CPUORG_SEMA0, 0x0028),
+ REG(DEV_CPUORG_SEMA0_OWNER, 0x002c),
+ REG(DEV_CPUORG_SEMA1, 0x0030),
+ REG(DEV_CPUORG_SEMA1_OWNER, 0x0034),
+};
+
+static const u32 vsc7512_gcb_regmap[] = {
+ REG(GCB_SOFT_RST, 0x0008),
+ REG(GCB_MIIM_MII_STATUS, 0x009c),
+ REG(GCB_MIIM_MII_CMD, 0x00a4),
+ REG(GCB_MIIM_MII_DATA, 0x00a8),
+ REG(GCB_PHY_PHY_CFG, 0x00f0),
+ REG(GCB_PHY_PHY_STAT, 0x00f4),
+};
+
+static const u32 *vsc7512_regmap[TARGET_MAX] = {
+ [ANA] = ocelot_ana_regmap,
+ [QS] = ocelot_qs_regmap,
+ [QSYS] = ocelot_qsys_regmap,
+ [REW] = ocelot_rew_regmap,
+ [SYS] = ocelot_sys_regmap,
+ [S0] = ocelot_vcap_regmap,
+ [S1] = ocelot_vcap_regmap,
+ [S2] = ocelot_vcap_regmap,
+ [PTP] = ocelot_ptp_regmap,
+ [GCB] = vsc7512_gcb_regmap,
+ [DEV_GMII] = ocelot_dev_gmii_regmap,
+ [DEV_CPUORG] = vsc7512_dev_cpuorg_regmap,
+};
+
+#define VSC7512_BYTE_ORDER_LE 0x00000000
+#define VSC7512_BYTE_ORDER_BE 0x81818181
+#define VSC7512_BIT_ORDER_MSB 0x00000000
+#define VSC7512_BIT_ORDER_LSB 0x42424242
+
+static void ocelot_spi_reset_phys(struct ocelot *ocelot)
+{
+ ocelot_write(ocelot, 0, GCB_PHY_PHY_CFG);
+ ocelot_write(ocelot, 0x1ff, GCB_PHY_PHY_CFG);
+ mdelay(500);
+}
+
+static struct ocelot_spi_data *felix_to_ocelot_spi(struct felix *felix)
+{
+ return container_of(felix, struct ocelot_spi_data, felix);
+}
+
+static struct ocelot_spi_data *ocelot_to_ocelot_spi(struct ocelot *ocelot)
+{
+ struct felix *felix = ocelot_to_felix(ocelot);
+
+ return felix_to_ocelot_spi(felix);
+}
+
+static int ocelot_spi_init_bus(struct ocelot *ocelot)
+{
+ struct ocelot_spi_data *ocelot_spi;
+ struct spi_device *spi;
+ u32 val, check;
+
+ ocelot_spi = ocelot_to_ocelot_spi(ocelot);
+ spi = ocelot_spi->spi;
+
+ val = 0;
+
+#ifdef __LITTLE_ENDIAN
+ val |= VSC7512_BYTE_ORDER_LE;
+#else
+ val |= VSC7512_BYTE_ORDER_BE;
+#endif
+
+ ocelot_write(ocelot, val, DEV_CPUORG_IF_CTRL);
+
+ val = ocelot_spi->spi_padding_bytes;
+ ocelot_write(ocelot, val, DEV_CPUORG_IF_CFGSTAT);
+
+ check = val | 0x02000000;
+
+ val = ocelot_read(ocelot, DEV_CPUORG_IF_CFGSTAT);
+ if (check != val) {
+ dev_err(&spi->dev,
+ "Error configuring SPI bus. V: 0x%08x != 0x%08x\n", val,
+ check);
+ return -ENODEV;
+ }
+
+ /* The internal copper phys need to be enabled before the mdio bus is
+ * scanned.
+ */
+ ocelot_spi_reset_phys(ocelot);
+
+ return 0;
+}
+
+static int vsc7512_reset(struct ocelot *ocelot)
+{
+ int retries = 100;
+ int ret, val;
+
+ ocelot_field_write(ocelot, GCB_SOFT_RST_CHIP_RST, 1);
+
+ /* Note: This is adapted from the PCIe reset strategy. The manual doesn't
+ * suggest how to do a reset over SPI, and the register strategy isn't
+ * possible.
+ */
+ msleep(100);
+
+ ret = ocelot_spi_init_bus(ocelot);
+ if (ret)
+ return ret;
+
+ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1);
+ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1);
+
+ do {
+ msleep(1);
+ regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT],
+ &val);
+ } while (val && --retries);
+
+ if (!retries)
+ return -ETIMEDOUT;
+
+ regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1);
+
+ return 0;
+}
+
+static int vsc7512_spi_bus_init(struct ocelot *ocelot)
+{
+ struct felix *felix = ocelot_to_felix(ocelot);
+ int rval;
+
+ rval = ocelot_spi_init_bus(ocelot);
+ if (rval) {
+ dev_err(ocelot->dev, "error initializing SPI bus\n");
+ goto clear_mdio;
+ }
+
+ rval = felix_mdio_register(ocelot);
+ if (rval)
+ dev_err(ocelot->dev, "error registering MDIO bus\n");
+
+ felix->ds->slave_mii_bus = felix->imdio;
+
+ return rval;
+
+clear_mdio:
+ felix->imdio = NULL;
+ return rval;
+}
+
+static const struct ocelot_ops vsc7512_ops = {
+ .bus_init = vsc7512_spi_bus_init,
+ .reset = vsc7512_reset,
+ .wm_enc = ocelot_wm_enc,
+ .wm_dec = ocelot_wm_dec,
+ .wm_stat = ocelot_wm_stat,
+ .port_to_netdev = felix_port_to_netdev,
+ .netdev_to_port = felix_netdev_to_port,
+};
+
+/* Addresses are relative to the SPI device's base address, downshifted by 2*/
+static const struct resource vsc7512_target_io_res[TARGET_MAX] = {
+ [ANA] = {
+ .start = 0x71880000,
+ .end = 0x7188ffff,
+ .name = "ana",
+ },
+ [QS] = {
+ .start = 0x71080000,
+ .end = 0x710800ff,
+ .name = "qs",
+ },
+ [QSYS] = {
+ .start = 0x71800000,
+ .end = 0x719fffff,
+ .name = "qsys",
+ },
+ [REW] = {
+ .start = 0x71030000,
+ .end = 0x7103ffff,
+ .name = "rew",
+ },
+ [SYS] = {
+ .start = 0x71010000,
+ .end = 0x7101ffff,
+ .name = "sys",
+ },
+ [S0] = {
+ .start = 0x71040000,
+ .end = 0x710403ff,
+ .name = "s0",
+ },
+ [S1] = {
+ .start = 0x71050000,
+ .end = 0x710503ff,
+ .name = "s1",
+ },
+ [S2] = {
+ .start = 0x71060000,
+ .end = 0x710603ff,
+ .name = "s2",
+ },
+ [GCB] = {
+ .start = 0x71070000,
+ .end = 0x710701ff,
+ .name = "devcpu_gcb",
+ },
+ [DEV_CPUORG] = {
+ .start = 0x71000000,
+ .end = 0x710003ff,
+ .name = "devcpu_org",
+ },
+};
+
+static const struct resource vsc7512_port_io_res[] = {
+ {
+ .start = 0x711e0000,
+ .end = 0x711effff,
+ .name = "port0",
+ },
+ {
+ .start = 0x711f0000,
+ .end = 0x711fffff,
+ .name = "port1",
+ },
+ {
+ .start = 0x71200000,
+ .end = 0x7120ffff,
+ .name = "port2",
+ },
+ {
+ .start = 0x71210000,
+ .end = 0x7121ffff,
+ .name = "port3",
+ },
+ {
+ .start = 0x71220000,
+ .end = 0x7122ffff,
+ .name = "port4",
+ },
+ {
+ .start = 0x71230000,
+ .end = 0x7123ffff,
+ .name = "port5",
+ },
+ {
+ .start = 0x71240000,
+ .end = 0x7124ffff,
+ .name = "port6",
+ },
+ {
+ .start = 0x71250000,
+ .end = 0x7125ffff,
+ .name = "port7",
+ },
+ {
+ .start = 0x71260000,
+ .end = 0x7126ffff,
+ .name = "port8",
+ },
+ {
+ .start = 0x71270000,
+ .end = 0x7127ffff,
+ .name = "port9",
+ },
+ {
+ .start = 0x71280000,
+ .end = 0x7128ffff,
+ .name = "port10",
+ },
+};
+
+static const struct reg_field vsc7512_regfields[REGFIELD_MAX] = {
+ [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 11, 11),
+ [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 10),
+ [ANA_ANEVENTS_MSTI_DROP] = REG_FIELD(ANA_ANEVENTS, 27, 27),
+ [ANA_ANEVENTS_ACLKILL] = REG_FIELD(ANA_ANEVENTS, 26, 26),
+ [ANA_ANEVENTS_ACLUSED] = REG_FIELD(ANA_ANEVENTS, 25, 25),
+ [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 24, 24),
+ [ANA_ANEVENTS_VS2TTL1] = REG_FIELD(ANA_ANEVENTS, 23, 23),
+ [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 22, 22),
+ [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 21, 21),
+ [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 20, 20),
+ [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 19, 19),
+ [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 18, 18),
+ [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 17, 17),
+ [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 16, 16),
+ [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 15, 15),
+ [ANA_ANEVENTS_DROPPED] = REG_FIELD(ANA_ANEVENTS, 14, 14),
+ [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 13, 13),
+ [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 12, 12),
+ [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 11, 11),
+ [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 10, 10),
+ [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 9, 9),
+ [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 8, 8),
+ [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 7, 7),
+ [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6),
+ [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5),
+ [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 4, 4),
+ [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 3, 3),
+ [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 2, 2),
+ [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 1, 1),
+ [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 0, 0),
+ [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 18, 18),
+ [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 10, 11),
+ [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 9),
+ [GCB_SOFT_RST_SWC_RST] = REG_FIELD(GCB_SOFT_RST, 1, 1),
+ [GCB_SOFT_RST_CHIP_RST] = REG_FIELD(GCB_SOFT_RST, 0, 0),
+ [QSYS_TIMED_FRAME_ENTRY_TFRM_VLD] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 20, 20),
+ [QSYS_TIMED_FRAME_ENTRY_TFRM_FP] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 8, 19),
+ [QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 4, 7),
+ [QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 1, 3),
+ [QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 0, 0),
+ [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 2, 2),
+ [SYS_RESET_CFG_MEM_ENA] = REG_FIELD(SYS_RESET_CFG, 1, 1),
+ [SYS_RESET_CFG_MEM_INIT] = REG_FIELD(SYS_RESET_CFG, 0, 0),
+ /* Replicated per number of ports (12), register size 4 per port */
+ [QSYS_SWITCH_PORT_MODE_PORT_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 14, 14, 12, 4),
+ [QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 11, 13, 12, 4),
+ [QSYS_SWITCH_PORT_MODE_YEL_RSRVD] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 10, 10, 12, 4),
+ [QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 9, 9, 12, 4),
+ [QSYS_SWITCH_PORT_MODE_TX_PFC_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 1, 8, 12, 4),
+ [QSYS_SWITCH_PORT_MODE_TX_PFC_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 0, 0, 12, 4),
+ [SYS_PORT_MODE_DATA_WO_TS] = REG_FIELD_ID(SYS_PORT_MODE, 5, 6, 12, 4),
+ [SYS_PORT_MODE_INCL_INJ_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 3, 4, 12, 4),
+ [SYS_PORT_MODE_INCL_XTR_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 1, 2, 12, 4),
+ [SYS_PORT_MODE_INCL_HDR_ERR] = REG_FIELD_ID(SYS_PORT_MODE, 0, 0, 12, 4),
+ [SYS_PAUSE_CFG_PAUSE_START] = REG_FIELD_ID(SYS_PAUSE_CFG, 10, 18, 12, 4),
+ [SYS_PAUSE_CFG_PAUSE_STOP] = REG_FIELD_ID(SYS_PAUSE_CFG, 1, 9, 12, 4),
+ [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 12, 4),
+ [GCB_MIIM_MII_STATUS_PENDING] = REG_FIELD(GCB_MIIM_MII_STATUS, 2, 2),
+ [GCB_MIIM_MII_STATUS_BUSY] = REG_FIELD(GCB_MIIM_MII_STATUS, 3, 3),
+};
+
+static const struct ocelot_stat_layout vsc7512_stats_layout[] = {
+ { .offset = 0x00, .name = "rx_octets", },
+ { .offset = 0x01, .name = "rx_unicast", },
+ { .offset = 0x02, .name = "rx_multicast", },
+ { .offset = 0x03, .name = "rx_broadcast", },
+ { .offset = 0x04, .name = "rx_shorts", },
+ { .offset = 0x05, .name = "rx_fragments", },
+ { .offset = 0x06, .name = "rx_jabbers", },
+ { .offset = 0x07, .name = "rx_crc_align_errs", },
+ { .offset = 0x08, .name = "rx_sym_errs", },
+ { .offset = 0x09, .name = "rx_frames_below_65_octets", },
+ { .offset = 0x0A, .name = "rx_frames_65_to_127_octets", },
+ { .offset = 0x0B, .name = "rx_frames_128_to_255_octets", },
+ { .offset = 0x0C, .name = "rx_frames_256_to_511_octets", },
+ { .offset = 0x0D, .name = "rx_frames_512_to_1023_octets", },
+ { .offset = 0x0E, .name = "rx_frames_1024_to_1526_octets", },
+ { .offset = 0x0F, .name = "rx_frames_over_1526_octets", },
+ { .offset = 0x10, .name = "rx_pause", },
+ { .offset = 0x11, .name = "rx_control", },
+ { .offset = 0x12, .name = "rx_longs", },
+ { .offset = 0x13, .name = "rx_classified_drops", },
+ { .offset = 0x14, .name = "rx_red_prio_0", },
+ { .offset = 0x15, .name = "rx_red_prio_1", },
+ { .offset = 0x16, .name = "rx_red_prio_2", },
+ { .offset = 0x17, .name = "rx_red_prio_3", },
+ { .offset = 0x18, .name = "rx_red_prio_4", },
+ { .offset = 0x19, .name = "rx_red_prio_5", },
+ { .offset = 0x1A, .name = "rx_red_prio_6", },
+ { .offset = 0x1B, .name = "rx_red_prio_7", },
+ { .offset = 0x1C, .name = "rx_yellow_prio_0", },
+ { .offset = 0x1D, .name = "rx_yellow_prio_1", },
+ { .offset = 0x1E, .name = "rx_yellow_prio_2", },
+ { .offset = 0x1F, .name = "rx_yellow_prio_3", },
+ { .offset = 0x20, .name = "rx_yellow_prio_4", },
+ { .offset = 0x21, .name = "rx_yellow_prio_5", },
+ { .offset = 0x22, .name = "rx_yellow_prio_6", },
+ { .offset = 0x23, .name = "rx_yellow_prio_7", },
+ { .offset = 0x24, .name = "rx_green_prio_0", },
+ { .offset = 0x25, .name = "rx_green_prio_1", },
+ { .offset = 0x26, .name = "rx_green_prio_2", },
+ { .offset = 0x27, .name = "rx_green_prio_3", },
+ { .offset = 0x28, .name = "rx_green_prio_4", },
+ { .offset = 0x29, .name = "rx_green_prio_5", },
+ { .offset = 0x2A, .name = "rx_green_prio_6", },
+ { .offset = 0x2B, .name = "rx_green_prio_7", },
+ { .offset = 0x40, .name = "tx_octets", },
+ { .offset = 0x41, .name = "tx_unicast", },
+ { .offset = 0x42, .name = "tx_multicast", },
+ { .offset = 0x43, .name = "tx_broadcast", },
+ { .offset = 0x44, .name = "tx_collision", },
+ { .offset = 0x45, .name = "tx_drops", },
+ { .offset = 0x46, .name = "tx_pause", },
+ { .offset = 0x47, .name = "tx_frames_below_65_octets", },
+ { .offset = 0x48, .name = "tx_frames_65_to_127_octets", },
+ { .offset = 0x49, .name = "tx_frames_128_255_octets", },
+ { .offset = 0x4A, .name = "tx_frames_256_511_octets", },
+ { .offset = 0x4B, .name = "tx_frames_512_1023_octets", },
+ { .offset = 0x4C, .name = "tx_frames_1024_1526_octets", },
+ { .offset = 0x4D, .name = "tx_frames_over_1526_octets", },
+ { .offset = 0x4E, .name = "tx_yellow_prio_0", },
+ { .offset = 0x4F, .name = "tx_yellow_prio_1", },
+ { .offset = 0x50, .name = "tx_yellow_prio_2", },
+ { .offset = 0x51, .name = "tx_yellow_prio_3", },
+ { .offset = 0x52, .name = "tx_yellow_prio_4", },
+ { .offset = 0x53, .name = "tx_yellow_prio_5", },
+ { .offset = 0x54, .name = "tx_yellow_prio_6", },
+ { .offset = 0x55, .name = "tx_yellow_prio_7", },
+ { .offset = 0x56, .name = "tx_green_prio_0", },
+ { .offset = 0x57, .name = "tx_green_prio_1", },
+ { .offset = 0x58, .name = "tx_green_prio_2", },
+ { .offset = 0x59, .name = "tx_green_prio_3", },
+ { .offset = 0x5A, .name = "tx_green_prio_4", },
+ { .offset = 0x5B, .name = "tx_green_prio_5", },
+ { .offset = 0x5C, .name = "tx_green_prio_6", },
+ { .offset = 0x5D, .name = "tx_green_prio_7", },
+ { .offset = 0x5E, .name = "tx_aged", },
+ { .offset = 0x80, .name = "drop_local", },
+ { .offset = 0x81, .name = "drop_tail", },
+ { .offset = 0x82, .name = "drop_yellow_prio_0", },
+ { .offset = 0x83, .name = "drop_yellow_prio_1", },
+ { .offset = 0x84, .name = "drop_yellow_prio_2", },
+ { .offset = 0x85, .name = "drop_yellow_prio_3", },
+ { .offset = 0x86, .name = "drop_yellow_prio_4", },
+ { .offset = 0x87, .name = "drop_yellow_prio_5", },
+ { .offset = 0x88, .name = "drop_yellow_prio_6", },
+ { .offset = 0x89, .name = "drop_yellow_prio_7", },
+ { .offset = 0x8A, .name = "drop_green_prio_0", },
+ { .offset = 0x8B, .name = "drop_green_prio_1", },
+ { .offset = 0x8C, .name = "drop_green_prio_2", },
+ { .offset = 0x8D, .name = "drop_green_prio_3", },
+ { .offset = 0x8E, .name = "drop_green_prio_4", },
+ { .offset = 0x8F, .name = "drop_green_prio_5", },
+ { .offset = 0x90, .name = "drop_green_prio_6", },
+ { .offset = 0x91, .name = "drop_green_prio_7", },
+};
+
+static unsigned int ocelot_spi_translate_address(unsigned int reg)
+{
+ return cpu_to_be32((reg & 0xffffff) >> 2);
+}
+
+struct ocelot_spi_regmap_context {
+ struct spi_device *spi;
+ u32 base;
+};
+
+static int ocelot_spi_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct ocelot_spi_regmap_context *regmap_context = context;
+ struct spi_transfer tx, padding, rx;
+ struct ocelot_spi_data *ocelot_spi;
+ struct spi_message msg;
+ struct spi_device *spi;
+ unsigned int addr;
+ u8 *tx_buf;
+
+ WARN_ON(!val);
+
+ spi = regmap_context->spi;
+
+ ocelot_spi = spi_get_drvdata(spi);
+
+ addr = ocelot_spi_translate_address(reg + regmap_context->base);
+ tx_buf = (u8 *)&addr;
+
+ spi_message_init(&msg);
+
+ memset(&tx, 0, sizeof(struct spi_transfer));
+
+ /* Ignore the first byte for the 24-bit address */
+ tx.tx_buf = &tx_buf[1];
+ tx.len = 3;
+
+ spi_message_add_tail(&tx, &msg);
+
+ if (ocelot_spi->spi_padding_bytes > 0) {
+ u8 dummy_buf[16] = {0};
+
+ memset(&padding, 0, sizeof(struct spi_transfer));
+
+ /* Just toggle the clock for padding bytes */
+ padding.len = ocelot_spi->spi_padding_bytes;
+ padding.tx_buf = dummy_buf;
+ padding.dummy_data = 1;
+
+ spi_message_add_tail(&padding, &msg);
+ }
+
+ memset(&rx, 0, sizeof(struct spi_transfer));
+ rx.rx_buf = val;
+ rx.len = 4;
+
+ spi_message_add_tail(&rx, &msg);
+
+ return spi_sync(spi, &msg);
+}
+
+static int ocelot_spi_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct ocelot_spi_regmap_context *regmap_context = context;
+ struct spi_transfer tx[2] = {0};
+ struct spi_message msg;
+ struct spi_device *spi;
+ unsigned int addr;
+ u8 *tx_buf;
+
+ spi = regmap_context->spi;
+
+ addr = ocelot_spi_translate_address(reg + regmap_context->base);
+ tx_buf = (u8 *)&addr;
+
+ spi_message_init(&msg);
+
+ /* Ignore the first byte for the 24-bit address and set the write bit */
+ tx_buf[1] |= BIT(7);
+ tx[0].tx_buf = &tx_buf[1];
+ tx[0].len = 3;
+
+ spi_message_add_tail(&tx[0], &msg);
+
+ memset(&tx[1], 0, sizeof(struct spi_transfer));
+ tx[1].tx_buf = &val;
+ tx[1].len = 4;
+
+ spi_message_add_tail(&tx[1], &msg);
+
+ return spi_sync(spi, &msg);
+}
+
+static const struct regmap_config ocelot_spi_regmap_config = {
+ .reg_bits = 24,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .reg_read = ocelot_spi_reg_read,
+ .reg_write = ocelot_spi_reg_write,
+
+ .max_register = 0xffffffff,
+ .use_single_write = true,
+ .use_single_read = true,
+ .can_multi_write = false,
+
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+};
+
+static void vsc7512_phylink_validate(struct ocelot *ocelot, int port,
+ unsigned long *supported,
+ struct phylink_link_state *state)
+{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
+
+ if (state->interface != PHY_INTERFACE_MODE_NA &&
+ state->interface != ocelot_port->phy_mode) {
+ bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ return;
+ }
+
+ phylink_set_port_modes(mask);
+
+ phylink_set(mask, Pause);
+ phylink_set(mask, Autoneg);
+ phylink_set(mask, Asym_Pause);
+ phylink_set(mask, 10baseT_Half);
+ phylink_set(mask, 10baseT_Full);
+ phylink_set(mask, 100baseT_Half);
+ phylink_set(mask, 100baseT_Full);
+ phylink_set(mask, 1000baseT_Half);
+ phylink_set(mask, 1000baseT_Full);
+
+ bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ bitmap_and(state->advertising, state->advertising, mask,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+}
+
+static int vsc7512_prevalidate_phy_mode(struct ocelot *ocelot, int port,
+ phy_interface_t phy_mode)
+{
+ switch (phy_mode) {
+ case PHY_INTERFACE_MODE_INTERNAL:
+ if (port < 4)
+ return 0;
+ return -EOPNOTSUPP;
+ case PHY_INTERFACE_MODE_SGMII:
+ if (port < 8)
+ return 0;
+ return -EOPNOTSUPP;
+ case PHY_INTERFACE_MODE_QSGMII:
+ if (port == 7 || port == 8 || port == 10)
+ return 0;
+ return -EOPNOTSUPP;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int vsc7512_port_setup_tc(struct dsa_switch *ds, int port,
+ enum tc_setup_type type, void *type_data)
+{
+ return -EOPNOTSUPP;
+}
+
+static const struct vcap_field vsc7512_vcap_es0_keys[] = {
+ [VCAP_ES0_EGR_PORT] = { 0, 4 },
+ [VCAP_ES0_IGR_PORT] = { 4, 4 },
+ [VCAP_ES0_RSV] = { 8, 2 },
+ [VCAP_ES0_L2_MC] = { 10, 1 },
+ [VCAP_ES0_L2_BC] = { 11, 1 },
+ [VCAP_ES0_VID] = { 12, 12 },
+ [VCAP_ES0_DP] = { 24, 1 },
+ [VCAP_ES0_PCP] = { 25, 3 },
+};
+
+static const struct vcap_field vsc7512_vcap_es0_actions[] = {
+ [VCAP_ES0_ACT_PUSH_OUTER_TAG] = { 0, 2 },
+ [VCAP_ES0_ACT_PUSH_INNER_TAG] = { 2, 1 },
+ [VCAP_ES0_ACT_TAG_A_TPID_SEL] = { 3, 2 },
+ [VCAP_ES0_ACT_TAG_A_VID_SEL] = { 5, 1 },
+ [VCAP_ES0_ACT_TAG_A_PCP_SEL] = { 6, 2 },
+ [VCAP_ES0_ACT_TAG_A_DEI_SEL] = { 8, 2 },
+ [VCAP_ES0_ACT_TAG_B_TPID_SEL] = { 10, 2 },
+ [VCAP_ES0_ACT_TAG_B_VID_SEL] = { 12, 1 },
+ [VCAP_ES0_ACT_TAG_B_PCP_SEL] = { 13, 2 },
+ [VCAP_ES0_ACT_TAG_B_DEI_SEL] = { 15, 2 },
+ [VCAP_ES0_ACT_VID_A_VAL] = { 17, 12 },
+ [VCAP_ES0_ACT_PCP_A_VAL] = { 29, 3 },
+ [VCAP_ES0_ACT_DEI_A_VAL] = { 32, 1 },
+ [VCAP_ES0_ACT_VID_B_VAL] = { 33, 12 },
+ [VCAP_ES0_ACT_PCP_B_VAL] = { 45, 3 },
+ [VCAP_ES0_ACT_DEI_B_VAL] = { 48, 1 },
+ [VCAP_ES0_ACT_RSV] = { 49, 24 },
+ [VCAP_ES0_ACT_HIT_STICKY] = { 73, 1 },
+};
+
+static const struct vcap_field vsc7512_vcap_is1_keys[] = {
+ [VCAP_IS1_HK_TYPE] = { 0, 1 },
+ [VCAP_IS1_HK_LOOKUP] = { 1, 2 },
+ [VCAP_IS1_HK_IGR_PORT_MASK] = { 3, 12 },
+ [VCAP_IS1_HK_RSV] = { 15, 9 },
+ [VCAP_IS1_HK_OAM_Y1731] = { 24, 1 },
+ [VCAP_IS1_HK_L2_MC] = { 25, 1 },
+ [VCAP_IS1_HK_L2_BC] = { 26, 1 },
+ [VCAP_IS1_HK_IP_MC] = { 27, 1 },
+ [VCAP_IS1_HK_VLAN_TAGGED] = { 28, 1 },
+ [VCAP_IS1_HK_VLAN_DBL_TAGGED] = { 29, 1 },
+ [VCAP_IS1_HK_TPID] = { 30, 1 },
+ [VCAP_IS1_HK_VID] = { 31, 12 },
+ [VCAP_IS1_HK_DEI] = { 43, 1 },
+ [VCAP_IS1_HK_PCP] = { 44, 3 },
+ /* Specific Fields for IS1 Half Key S1_NORMAL */
+ [VCAP_IS1_HK_L2_SMAC] = { 47, 48 },
+ [VCAP_IS1_HK_ETYPE_LEN] = { 95, 1 },
+ [VCAP_IS1_HK_ETYPE] = { 96, 16 },
+ [VCAP_IS1_HK_IP_SNAP] = { 112, 1 },
+ [VCAP_IS1_HK_IP4] = { 113, 1 },
+ /* Layer-3 Information */
+ [VCAP_IS1_HK_L3_FRAGMENT] = { 114, 1 },
+ [VCAP_IS1_HK_L3_FRAG_OFS_GT0] = { 115, 1 },
+ [VCAP_IS1_HK_L3_OPTIONS] = { 116, 1 },
+ [VCAP_IS1_HK_L3_DSCP] = { 117, 6 },
+ [VCAP_IS1_HK_L3_IP4_SIP] = { 123, 32 },
+ /* Layer-4 Information */
+ [VCAP_IS1_HK_TCP_UDP] = { 155, 1 },
+ [VCAP_IS1_HK_TCP] = { 156, 1 },
+ [VCAP_IS1_HK_L4_SPORT] = { 157, 16 },
+ [VCAP_IS1_HK_L4_RNG] = { 173, 8 },
+ /* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */
+ [VCAP_IS1_HK_IP4_INNER_TPID] = { 47, 1 },
+ [VCAP_IS1_HK_IP4_INNER_VID] = { 48, 12 },
+ [VCAP_IS1_HK_IP4_INNER_DEI] = { 60, 1 },
+ [VCAP_IS1_HK_IP4_INNER_PCP] = { 61, 3 },
+ [VCAP_IS1_HK_IP4_IP4] = { 64, 1 },
+ [VCAP_IS1_HK_IP4_L3_FRAGMENT] = { 65, 1 },
+ [VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0] = { 66, 1 },
+ [VCAP_IS1_HK_IP4_L3_OPTIONS] = { 67, 1 },
+ [VCAP_IS1_HK_IP4_L3_DSCP] = { 68, 6 },
+ [VCAP_IS1_HK_IP4_L3_IP4_DIP] = { 74, 32 },
+ [VCAP_IS1_HK_IP4_L3_IP4_SIP] = { 106, 32 },
+ [VCAP_IS1_HK_IP4_L3_PROTO] = { 138, 8 },
+ [VCAP_IS1_HK_IP4_TCP_UDP] = { 146, 1 },
+ [VCAP_IS1_HK_IP4_TCP] = { 147, 1 },
+ [VCAP_IS1_HK_IP4_L4_RNG] = { 148, 8 },
+ [VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE] = { 156, 32 },
+};
+
+static const struct vcap_field vsc7512_vcap_is1_actions[] = {
+ [VCAP_IS1_ACT_DSCP_ENA] = { 0, 1 },
+ [VCAP_IS1_ACT_DSCP_VAL] = { 1, 6 },
+ [VCAP_IS1_ACT_QOS_ENA] = { 7, 1 },
+ [VCAP_IS1_ACT_QOS_VAL] = { 8, 3 },
+ [VCAP_IS1_ACT_DP_ENA] = { 11, 1 },
+ [VCAP_IS1_ACT_DP_VAL] = { 12, 1 },
+ [VCAP_IS1_ACT_PAG_OVERRIDE_MASK] = { 13, 8 },
+ [VCAP_IS1_ACT_PAG_VAL] = { 21, 8 },
+ [VCAP_IS1_ACT_RSV] = { 29, 9 },
+ /* The fields below are incorrectly shifted by 2 in the manual */
+ [VCAP_IS1_ACT_VID_REPLACE_ENA] = { 38, 1 },
+ [VCAP_IS1_ACT_VID_ADD_VAL] = { 39, 12 },
+ [VCAP_IS1_ACT_FID_SEL] = { 51, 2 },
+ [VCAP_IS1_ACT_FID_VAL] = { 53, 13 },
+ [VCAP_IS1_ACT_PCP_DEI_ENA] = { 66, 1 },
+ [VCAP_IS1_ACT_PCP_VAL] = { 67, 3 },
+ [VCAP_IS1_ACT_DEI_VAL] = { 70, 1 },
+ [VCAP_IS1_ACT_VLAN_POP_CNT_ENA] = { 71, 1 },
+ [VCAP_IS1_ACT_VLAN_POP_CNT] = { 72, 2 },
+ [VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA] = { 74, 4 },
+ [VCAP_IS1_ACT_HIT_STICKY] = { 78, 1 },
+};
+
+static const struct vcap_field vsc7512_vcap_is2_keys[] = {
+ /* Common: 46 bits */
+ [VCAP_IS2_TYPE] = { 0, 4 },
+ [VCAP_IS2_HK_FIRST] = { 4, 1 },
+ [VCAP_IS2_HK_PAG] = { 5, 8 },
+ [VCAP_IS2_HK_IGR_PORT_MASK] = { 13, 12 },
+ [VCAP_IS2_HK_RSV2] = { 25, 1 },
+ [VCAP_IS2_HK_HOST_MATCH] = { 26, 1 },
+ [VCAP_IS2_HK_L2_MC] = { 27, 1 },
+ [VCAP_IS2_HK_L2_BC] = { 28, 1 },
+ [VCAP_IS2_HK_VLAN_TAGGED] = { 29, 1 },
+ [VCAP_IS2_HK_VID] = { 30, 12 },
+ [VCAP_IS2_HK_DEI] = { 42, 1 },
+ [VCAP_IS2_HK_PCP] = { 43, 3 },
+ /* MAC_ETYPE / MAC_LLC / MAC_SNAP / OAM common */
+ [VCAP_IS2_HK_L2_DMAC] = { 46, 48 },
+ [VCAP_IS2_HK_L2_SMAC] = { 94, 48 },
+ /* MAC_ETYPE (TYPE=000) */
+ [VCAP_IS2_HK_MAC_ETYPE_ETYPE] = { 142, 16 },
+ [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0] = { 158, 16 },
+ [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1] = { 174, 8 },
+ [VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2] = { 182, 3 },
+ /* MAC_LLC (TYPE=001) */
+ [VCAP_IS2_HK_MAC_LLC_L2_LLC] = { 142, 40 },
+ /* MAC_SNAP (TYPE=010) */
+ [VCAP_IS2_HK_MAC_SNAP_L2_SNAP] = { 142, 40 },
+ /* MAC_ARP (TYPE=011) */
+ [VCAP_IS2_HK_MAC_ARP_SMAC] = { 46, 48 },
+ [VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK] = { 94, 1 },
+ [VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK] = { 95, 1 },
+ [VCAP_IS2_HK_MAC_ARP_LEN_OK] = { 96, 1 },
+ [VCAP_IS2_HK_MAC_ARP_TARGET_MATCH] = { 97, 1 },
+ [VCAP_IS2_HK_MAC_ARP_SENDER_MATCH] = { 98, 1 },
+ [VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN] = { 99, 1 },
+ [VCAP_IS2_HK_MAC_ARP_OPCODE] = { 100, 2 },
+ [VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP] = { 102, 32 },
+ [VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP] = { 134, 32 },
+ [VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP] = { 166, 1 },
+ /* IP4_TCP_UDP / IP4_OTHER common */
+ [VCAP_IS2_HK_IP4] = { 46, 1 },
+ [VCAP_IS2_HK_L3_FRAGMENT] = { 47, 1 },
+ [VCAP_IS2_HK_L3_FRAG_OFS_GT0] = { 48, 1 },
+ [VCAP_IS2_HK_L3_OPTIONS] = { 49, 1 },
+ [VCAP_IS2_HK_IP4_L3_TTL_GT0] = { 50, 1 },
+ [VCAP_IS2_HK_L3_TOS] = { 51, 8 },
+ [VCAP_IS2_HK_L3_IP4_DIP] = { 59, 32 },
+ [VCAP_IS2_HK_L3_IP4_SIP] = { 91, 32 },
+ [VCAP_IS2_HK_DIP_EQ_SIP] = { 123, 1 },
+ /* IP4_TCP_UDP (TYPE=100) */
+ [VCAP_IS2_HK_TCP] = { 124, 1 },
+ [VCAP_IS2_HK_L4_DPORT] = { 125, 16 },
+ [VCAP_IS2_HK_L4_SPORT] = { 141, 16 },
+ [VCAP_IS2_HK_L4_RNG] = { 157, 8 },
+ [VCAP_IS2_HK_L4_SPORT_EQ_DPORT] = { 165, 1 },
+ [VCAP_IS2_HK_L4_SEQUENCE_EQ0] = { 166, 1 },
+ [VCAP_IS2_HK_L4_FIN] = { 167, 1 },
+ [VCAP_IS2_HK_L4_SYN] = { 168, 1 },
+ [VCAP_IS2_HK_L4_RST] = { 169, 1 },
+ [VCAP_IS2_HK_L4_PSH] = { 170, 1 },
+ [VCAP_IS2_HK_L4_ACK] = { 171, 1 },
+ [VCAP_IS2_HK_L4_URG] = { 172, 1 },
+ [VCAP_IS2_HK_L4_1588_DOM] = { 173, 8 },
+ [VCAP_IS2_HK_L4_1588_VER] = { 181, 4 },
+ /* IP4_OTHER (TYPE=101) */
+ [VCAP_IS2_HK_IP4_L3_PROTO] = { 124, 8 },
+ [VCAP_IS2_HK_L3_PAYLOAD] = { 132, 56 },
+ /* IP6_STD (TYPE=110) */
+ [VCAP_IS2_HK_IP6_L3_TTL_GT0] = { 46, 1 },
+ [VCAP_IS2_HK_L3_IP6_SIP] = { 47, 128 },
+ [VCAP_IS2_HK_IP6_L3_PROTO] = { 175, 8 },
+ /* OAM (TYPE=111) */
+ [VCAP_IS2_HK_OAM_MEL_FLAGS] = { 142, 7 },
+ [VCAP_IS2_HK_OAM_VER] = { 149, 5 },
+ [VCAP_IS2_HK_OAM_OPCODE] = { 154, 8 },
+ [VCAP_IS2_HK_OAM_FLAGS] = { 162, 8 },
+ [VCAP_IS2_HK_OAM_MEPID] = { 170, 16 },
+ [VCAP_IS2_HK_OAM_CCM_CNTS_EQ0] = { 186, 1 },
+ [VCAP_IS2_HK_OAM_IS_Y1731] = { 187, 1 },
+};
+
+static const struct vcap_field vsc7512_vcap_is2_actions[] = {
+ [VCAP_IS2_ACT_HIT_ME_ONCE] = { 0, 1 },
+ [VCAP_IS2_ACT_CPU_COPY_ENA] = { 1, 1 },
+ [VCAP_IS2_ACT_CPU_QU_NUM] = { 2, 3 },
+ [VCAP_IS2_ACT_MASK_MODE] = { 5, 2 },
+ [VCAP_IS2_ACT_MIRROR_ENA] = { 7, 1 },
+ [VCAP_IS2_ACT_LRN_DIS] = { 8, 1 },
+ [VCAP_IS2_ACT_POLICE_ENA] = { 9, 1 },
+ [VCAP_IS2_ACT_POLICE_IDX] = { 10, 9 },
+ [VCAP_IS2_ACT_POLICE_VCAP_ONLY] = { 19, 1 },
+ [VCAP_IS2_ACT_PORT_MASK] = { 20, 11 },
+ [VCAP_IS2_ACT_REW_OP] = { 31, 9 },
+ [VCAP_IS2_ACT_SMAC_REPLACE_ENA] = { 40, 1 },
+ [VCAP_IS2_ACT_RSV] = { 41, 2 },
+ [VCAP_IS2_ACT_ACL_ID] = { 43, 6 },
+ [VCAP_IS2_ACT_HIT_CNT] = { 49, 32 },
+};
+
+static struct vcap_props vsc7512_vcap_props[] = {
+ [VCAP_ES0] = {
+ .action_type_width = 0,
+ .action_table = {
+ [ES0_ACTION_TYPE_NORMAL] = {
+ .width = 73,
+ .count = 1,
+ },
+ },
+ .target = S0,
+ .keys = vsc7512_vcap_es0_keys,
+ .actions = vsc7512_vcap_es0_actions,
+ },
+ [VCAP_IS1] = {
+ .action_type_width = 0,
+ .action_table = {
+ [IS1_ACTION_TYPE_NORMAL] = {
+ .width = 78,
+ .count = 4,
+ },
+ },
+ .target = S1,
+ .keys = vsc7512_vcap_is1_keys,
+ .actions = vsc7512_vcap_is1_actions,
+ },
+ [VCAP_IS2] = {
+ .action_type_width = 1,
+ .action_table = {
+ [IS2_ACTION_TYPE_NORMAL] = {
+ .width = 49,
+ .count = 2,
+ },
+ [IS2_ACTION_TYPE_SMAC_SIP] = {
+ .width = 6,
+ .count = 4,
+ },
+ },
+ .target = S2,
+ .keys = vsc7512_vcap_is2_keys,
+ .actions = vsc7512_vcap_is2_actions,
+ },
+};
+
+static struct regmap *vsc7512_regmap_init(struct ocelot *ocelot,
+ struct resource *res)
+{
+ struct ocelot_spi_regmap_context *context;
+ struct regmap_config regmap_config;
+ struct ocelot_spi_data *ocelot_spi;
+ struct regmap *regmap;
+ struct device *dev;
+ char name[32];
+
+ ocelot_spi = ocelot_to_ocelot_spi(ocelot);
+ dev = &ocelot_spi->spi->dev;
+
+ context = devm_kzalloc(dev, sizeof(struct ocelot_spi_regmap_context),
+ GFP_KERNEL);
+
+ if (IS_ERR(context))
+ return ERR_CAST(context);
+
+ context->base = res->start;
+ context->spi = ocelot_spi->spi;
+
+ memcpy(&regmap_config, &ocelot_spi_regmap_config,
+ sizeof(ocelot_spi_regmap_config));
+
+ /* A unique bus name is required for each regmap */
+ if (res->name)
+ snprintf(name, sizeof(name) - 1, "ocelot_spi-%s", res->name);
+ else
+ snprintf(name, sizeof(name) - 1, "ocelot_spi@0x%08x",
+ res->start);
+
+ regmap_config.name = name;
+ regmap_config.max_register = res->end - res->start;
+
+ regmap = devm_regmap_init(dev, NULL, context, &regmap_config);
+
+ if (IS_ERR(regmap))
+ return ERR_CAST(regmap);
+
+ return regmap;
+}
+
+/* Code taken from ocelot_adjust_link. Since we don't have a phydev, and
+ * therefore a phydev->link associated with the NPI port, it needs to be enabled
+ * blindly.
+ */
+static void vsc7512_enable_npi_port(struct ocelot *ocelot)
+{
+ struct ocelot_port *npi_port = ocelot->ports[ocelot->npi];
+
+ /* Assuming 1Gbps max speed to the CPU */
+ ocelot_port_writel(npi_port, DEV_MAC_MODE_CFG_FDX_ENA |
+ OCELOT_SPEED_1000, DEV_MAC_MODE_CFG);
+
+ /* Disable HDX fast control */
+ ocelot_port_writel(npi_port, DEV_PORT_MISC_HDX_FAST_DIS, DEV_PORT_MISC);
+
+ /* Enable SGMII */
+ ocelot_port_writel(npi_port, PCS1G_MODE_CFG_SGMII_MODE_ENA,
+ PCS1G_MODE_CFG);
+ ocelot_port_writel(npi_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG);
+
+ /* Enable PCS */
+ ocelot_port_writel(npi_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG);
+
+ /* Disable aneg and loopback */
+ ocelot_port_writel(npi_port, 0, PCS1G_ANEG_CFG);
+ ocelot_port_writel(npi_port, 0, PCS1G_LB_CFG);
+
+ /* Enable MAC module */
+ ocelot_port_writel(npi_port, DEV_MAC_ENA_CFG_RX_ENA |
+ DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG);
+
+ /* Take MAC, Port, Phy and PCS clock out of reset */
+ ocelot_port_writel(npi_port,
+ DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000),
+ DEV_CLOCK_CFG);
+
+ /* No PFS */
+ ocelot_write_gix(ocelot,
+ ANA_PFC_PFC_CFG_FC_LINK_SPEED(OCELOT_SPEED_1000),
+ ANA_PFC_PFC_CFG, ocelot->npi);
+
+ /* Enable port for frame transfer */
+ ocelot_fields_write(ocelot, ocelot->npi,
+ QSYS_SWITCH_PORT_MODE_PORT_ENA, 1);
+
+ /* Flow control */
+ ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) |
+ SYS_MAC_FC_CFG_RX_FC_ENA | SYS_MAC_FC_CFG_TX_FC_ENA |
+ SYS_MAC_FC_CFG_ZERO_PAUSE_ENA |
+ SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) |
+ SYS_MAC_FC_CFG_FC_LINK_SPEED(OCELOT_SPEED_1000),
+ SYS_MAC_FC_CFG, ocelot->npi);
+ ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, ocelot->npi);
+
+ /* Enable receiving frames on the port, and auto-learning of MAC
+ * addresses.
+ */
+ ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO |
+ ANA_PORT_PORT_CFG_RECV_ENA |
+ ANA_PORT_PORT_CFG_PORTID_VAL(ocelot->npi),
+ ANA_PORT_PORT_CFG, ocelot->npi);
+}
+
+static const struct felix_info ocelot_spi_info = {
+ .target_io_res = vsc7512_target_io_res,
+ .port_io_res = vsc7512_port_io_res,
+ .regfields = vsc7512_regfields,
+ .map = vsc7512_regmap,
+ .ops = &vsc7512_ops,
+ .stats_layout = vsc7512_stats_layout,
+ .num_stats = ARRAY_SIZE(vsc7512_stats_layout),
+ .vcap = vsc7512_vcap_props,
+ .num_mact_rows = 1024,
+ .num_ports = 11,
+ .num_tx_queues = OCELOT_NUM_TC,
+ .mdio_bus_alloc = felix_mdio_bus_alloc,
+ .mdio_bus_free = felix_mdio_bus_free,
+ .phylink_validate = vsc7512_phylink_validate,
+ .prevalidate_phy_mode = vsc7512_prevalidate_phy_mode,
+ .port_setup_tc = vsc7512_port_setup_tc,
+ .init_regmap = vsc7512_regmap_init,
+ .enable_npi_port = vsc7512_enable_npi_port,
+};
+
+static int ocelot_spi_probe(struct spi_device *spi)
+{
+ struct ocelot_spi_data *ocelot_spi;
+ struct dsa_switch *ds;
+ struct ocelot *ocelot;
+ struct felix *felix;
+ struct device *dev;
+ int err;
+
+ dev = &spi->dev;
+
+ ocelot_spi = devm_kzalloc(dev, sizeof(struct ocelot_spi_data),
+ GFP_KERNEL);
+
+ if (!ocelot_spi)
+ return -ENOMEM;
+
+ if (spi->max_speed_hz <= 500000) {
+ ocelot_spi->spi_padding_bytes = 0;
+ } else {
+ /* Calculation taken from the manual for IF_CFGSTAT:IF_CFG. Err
+ * on the side of more padding bytes, as having too few can be
+ * difficult to detect at runtime.
+ */
+ ocelot_spi->spi_padding_bytes = 1 +
+ (spi->max_speed_hz / 1000000 + 2) / 8;
+ }
+
+ dev_set_drvdata(dev, ocelot_spi);
+ ocelot_spi->spi = spi;
+
+ spi->bits_per_word = 8;
+
+ err = spi_setup(spi);
+ if (err < 0) {
+ dev_err(&spi->dev, "Error %d initializing SPI\n", err);
+ return err;
+ }
+
+ felix = &ocelot_spi->felix;
+
+ ocelot = &felix->ocelot;
+ ocelot->dev = dev;
+
+ ocelot->num_flooding_pgids = 1;
+
+ felix->info = &ocelot_spi_info;
+
+ ds = kzalloc(sizeof(*ds), GFP_KERNEL);
+ if (!ds) {
+ err = -ENOMEM;
+ dev_err(dev, "Failed to allocate DSA switch\n");
+ return err;
+ }
+
+ ds->dev = &spi->dev;
+ ds->num_ports = felix->info->num_ports;
+ ds->num_tx_queues = felix->info->num_tx_queues;
+
+ ds->ops = &felix_switch_ops;
+ ds->priv = ocelot;
+ felix->ds = ds;
+ felix->tag_proto = DSA_TAG_PROTO_OCELOT;
+
+ err = dsa_register_switch(ds);
+
+ if (err) {
+ dev_err(dev, "Failed to register DSA switch: %d\n", err);
+ goto err_register_ds;
+ }
+
+ return 0;
+
+err_register_ds:
+ kfree(ds);
+ return err;
+}
+
+static int ocelot_spi_remove(struct spi_device *spi)
+{
+ struct ocelot_spi_data *ocelot_spi;
+ struct felix *felix;
+
+ ocelot_spi = spi_get_drvdata(spi);
+ felix = &ocelot_spi->felix;
+
+ dsa_unregister_switch(felix->ds);
+
+ kfree(felix->ds);
+
+ devm_kfree(&spi->dev, ocelot_spi);
+
+ return 0;
+}
+
+const struct of_device_id vsc7512_of_match[] = {
+ { .compatible = "mscc,vsc7514" },
+ { .compatible = "mscc,vsc7513" },
+ { .compatible = "mscc,vsc7512" },
+ { .compatible = "mscc,vsc7511" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, vsc7512_of_match);
+
+static struct spi_driver ocelot_vsc7512_spi_driver = {
+ .driver = {
+ .name = "vsc7512",
+ .of_match_table = of_match_ptr(vsc7512_of_match),
+ },
+ .probe = ocelot_spi_probe,
+ .remove = ocelot_spi_remove,
+};
+module_spi_driver(ocelot_vsc7512_spi_driver);
+
+MODULE_DESCRIPTION("Ocelot Switch SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index adfb9781799e..10937dc59fce 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -2016,6 +2016,14 @@ int ocelot_init(struct ocelot *ocelot)
int i, ret;
u32 port;

+ if (ocelot->ops->bus_init) {
+ ret = ocelot->ops->bus_init(ocelot);
+ if (ret) {
+ dev_err(ocelot->dev, "Bus init failed\n");
+ return ret;
+ }
+ }
+
if (ocelot->ops->reset) {
ret = ocelot->ops->reset(ocelot);
if (ret) {
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index ff6e65a266d6..f5383804e724 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -129,6 +129,7 @@ enum ocelot_target {
PTP,
GCB,
DEV_GMII,
+ DEV_CPUORG,
TARGET_MAX,
};

@@ -407,6 +408,8 @@ enum ocelot_reg {
GCB_MIIM_MII_STATUS,
GCB_MIIM_MII_CMD,
GCB_MIIM_MII_DATA,
+ GCB_PHY_PHY_CFG,
+ GCB_PHY_PHY_STAT,
DEV_CLOCK_CFG = DEV_GMII << TARGET_OFFSET,
DEV_PORT_MISC,
DEV_EVENTS,
@@ -446,6 +449,20 @@ enum ocelot_reg {
PCS1G_TSTPAT_STATUS,
DEV_PCS_FX100_CFG,
DEV_PCS_FX100_STATUS,
+ DEV_CPUORG_IF_CTRL = DEV_CPUORG << TARGET_OFFSET,
+ DEV_CPUORG_IF_CFGSTAT,
+ DEV_CPUORG_ORG_CFG,
+ DEV_CPUORG_ERR_CNTS,
+ DEV_CPUORG_TIMEOUT_CFG,
+ DEV_CPUORG_GPR,
+ DEV_CPUORG_MAILBOX_SET,
+ DEV_CPUORG_MAILBOX_CLR,
+ DEV_CPUORG_MAILBOX,
+ DEV_CPUORG_SEMA_CFG,
+ DEV_CPUORG_SEMA0,
+ DEV_CPUORG_SEMA0_OWNER,
+ DEV_CPUORG_SEMA1,
+ DEV_CPUORG_SEMA1_OWNER,
};

enum ocelot_regfield {
@@ -504,6 +521,7 @@ enum ocelot_regfield {
SYS_RESET_CFG_MEM_ENA,
SYS_RESET_CFG_MEM_INIT,
GCB_SOFT_RST_SWC_RST,
+ GCB_SOFT_RST_CHIP_RST,
GCB_MIIM_MII_STATUS_PENDING,
GCB_MIIM_MII_STATUS_BUSY,
SYS_PAUSE_CFG_PAUSE_START,
@@ -560,6 +578,7 @@ struct ocelot;
struct ocelot_ops {
struct net_device *(*port_to_netdev)(struct ocelot *ocelot, int port);
int (*netdev_to_port)(struct net_device *dev);
+ int (*bus_init)(struct ocelot *ocelot);
int (*reset)(struct ocelot *ocelot);
u16 (*wm_enc)(u16 value);
u16 (*wm_dec)(u16 value);
--
2.25.1

2021-08-14 11:16:59

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 06/10] net: mscc: ocelot: split register definitions to a separate file

On Fri, Aug 13, 2021 at 07:49:59PM -0700, Colin Foster wrote:
> Moving these to a separate file will allow them to be shared to other
> drivers.
>
> Signed-off-by: Colin Foster <[email protected]>
> ---

What about the VCAP bit fields?

2021-08-14 11:45:00

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 09/10] net: dsa: ocelot: felix: add support for VSC75XX control over SPI

On Fri, Aug 13, 2021 at 07:50:02PM -0700, Colin Foster wrote:
> +/* Code taken from ocelot_adjust_link. Since we don't have a phydev, and
> + * therefore a phydev->link associated with the NPI port, it needs to be enabled
> + * blindly.
> + */

This makes no sense. You do have a phylink associated with the NPI port,
see for yourself, all of felix_phylink_mac_link_up, felix_phylink_mac_config,
felix_phylink_validate get called for the NPI port.

The trouble, really, is that what is done in felix_phylink_mac_link_up
is not sufficient for your hardware. The felix_vsc9959 and seville_vsc9953
drivers are Microchip switches integrated with NXP PCS, and the NXP PCS
has a dedicated driver in drivers/net/pcs/pcs-lynx.c.

So you won't see any of the PCS1G writes in the common driver, because
NXP integrations of these switches don't have that block.

This is not the proper way to do things. You are "fixing" SGMII for the
NPI/CPU port by pretending it's an NPI port issue, but in reality all
the other ports that use SGMII need the same treatment.

What we might need is a dedicated PCS driver for the VSC7512 switch, and
a way for the felix driver to interchangeably work with either struct
lynx_pcs or struct ocelot_pcs (or whatever it's going to be called).

The issue is that the registers for the PCS1G block look nothing like
the MDIO clause 22 layout, so anything that tries to map the struct
ocelot_pcs over a struct mdio_device is going to look like a horrible
shoehorn.

For that we might need Russell's assistance.

The documentation is at:
http://ww1.microchip.com/downloads/en/DeviceDoc/VMDS-10489.pdf
search for "Information about the registers for this product is available in the attached file."
and then open the PDF embedded within the PDF.

2021-08-14 12:08:19

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 09/10] net: dsa: ocelot: felix: add support for VSC75XX control over SPI

On Sat, Aug 14, 2021 at 02:43:29PM +0300, Vladimir Oltean wrote:
> The issue is that the registers for the PCS1G block look nothing like
> the MDIO clause 22 layout, so anything that tries to map the struct
> ocelot_pcs over a struct mdio_device is going to look like a horrible
> shoehorn.
>
> For that we might need Russell's assistance.
>
> The documentation is at:
> http://ww1.microchip.com/downloads/en/DeviceDoc/VMDS-10489.pdf
> search for "Information about the registers for this product is available in the attached file."
> and then open the PDF embedded within the PDF.

In fact I do notice now that as long as you don't use any of the
optional phylink_mii_c22_pcs_* helpers in your PCS driver, then
struct phylink_pcs has pretty much zero dependency on struct mdio_device,
which means that I'm wrong and it should be completely within reach to
write a dedicated PCS driver for this hardware.

As to how to make the common felix.c work with different implementations
of struct phylink_pcs, one thing that certainly has to change is that
struct felix should hold a struct phylink_pcs **pcs and not a
struct lynx_pcs **pcs.

Does this mean that we should refactor lynx_pcs_create() to return a
struct phylink_pcs * instead of struct lynx_pcs *, and lynx_pcs_destroy()
to receive the struct phylink_pcs *, use container_of() and free the
larger struct lynx_pcs *? Yes, probably.

If you feel uncomfortable with this, I can try to refactor lynx_pcs to
make it easier to accomodate a different PCS driver in felix.

2021-08-14 16:35:39

by Colin Foster

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 06/10] net: mscc: ocelot: split register definitions to a separate file

On Sat, Aug 14, 2021 at 02:15:09PM +0300, Vladimir Oltean wrote:
> On Fri, Aug 13, 2021 at 07:49:59PM -0700, Colin Foster wrote:
> > Moving these to a separate file will allow them to be shared to other
> > drivers.
> >
> > Signed-off-by: Colin Foster <[email protected]>
> > ---
>
> What about the VCAP bit fields?

Good find. I'll break those out and delete my duplicate copies.

2021-08-14 17:01:37

by Alexandre Belloni

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 06/10] net: mscc: ocelot: split register definitions to a separate file

Hello,

On 13/08/2021 19:49:59-0700, Colin Foster wrote:
> Moving these to a separate file will allow them to be shared to other
> drivers.
>
> Signed-off-by: Colin Foster <[email protected]>
> ---
> drivers/net/ethernet/mscc/Makefile | 1 +
> drivers/net/ethernet/mscc/ocelot_regs.c | 309 +++++++++++++++++++++

Maybe this should be named
drivers/net/ethernet/mscc/ocelot_vsc7514_regs.c in the case we had more
chips later on. The naming we chose is that ocelot refers generically to
the switch IP instead of a specific implementation.

> drivers/net/ethernet/mscc/ocelot_vsc7514.c | 295 +-------------------
> include/soc/mscc/ocelot_regs.h | 20 ++
> 4 files changed, 331 insertions(+), 294 deletions(-)
> create mode 100644 drivers/net/ethernet/mscc/ocelot_regs.c
> create mode 100644 include/soc/mscc/ocelot_regs.h
>
> diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile
> index 722c27694b21..d539a231a478 100644
> --- a/drivers/net/ethernet/mscc/Makefile
> +++ b/drivers/net/ethernet/mscc/Makefile
> @@ -7,6 +7,7 @@ mscc_ocelot_switch_lib-y := \
> ocelot_vcap.o \
> ocelot_flower.o \
> ocelot_ptp.o \
> + ocelot_regs.o \
> ocelot_devlink.o
> mscc_ocelot_switch_lib-$(CONFIG_BRIDGE_MRP) += ocelot_mrp.o
> obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot.o
> diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c
> new file mode 100644
> index 000000000000..b7ba137a7c90
> --- /dev/null
> +++ b/drivers/net/ethernet/mscc/ocelot_regs.c
> @@ -0,0 +1,309 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Microsemi Ocelot Switch driver
> + *
> + * Copyright (c) 2017 Microsemi Corporation
> + */
> +#include "ocelot.h"
> +
> +const u32 ocelot_ana_regmap[] = {
> + REG(ANA_ADVLEARN, 0x009000),
> + REG(ANA_VLANMASK, 0x009004),
> + REG(ANA_PORT_B_DOMAIN, 0x009008),
> + REG(ANA_ANAGEFIL, 0x00900c),
> + REG(ANA_ANEVENTS, 0x009010),
> + REG(ANA_STORMLIMIT_BURST, 0x009014),
> + REG(ANA_STORMLIMIT_CFG, 0x009018),
> + REG(ANA_ISOLATED_PORTS, 0x009028),
> + REG(ANA_COMMUNITY_PORTS, 0x00902c),
> + REG(ANA_AUTOAGE, 0x009030),
> + REG(ANA_MACTOPTIONS, 0x009034),
> + REG(ANA_LEARNDISC, 0x009038),
> + REG(ANA_AGENCTRL, 0x00903c),
> + REG(ANA_MIRRORPORTS, 0x009040),
> + REG(ANA_EMIRRORPORTS, 0x009044),
> + REG(ANA_FLOODING, 0x009048),
> + REG(ANA_FLOODING_IPMC, 0x00904c),
> + REG(ANA_SFLOW_CFG, 0x009050),
> + REG(ANA_PORT_MODE, 0x009080),
> + REG(ANA_PGID_PGID, 0x008c00),
> + REG(ANA_TABLES_ANMOVED, 0x008b30),
> + REG(ANA_TABLES_MACHDATA, 0x008b34),
> + REG(ANA_TABLES_MACLDATA, 0x008b38),
> + REG(ANA_TABLES_MACACCESS, 0x008b3c),
> + REG(ANA_TABLES_MACTINDX, 0x008b40),
> + REG(ANA_TABLES_VLANACCESS, 0x008b44),
> + REG(ANA_TABLES_VLANTIDX, 0x008b48),
> + REG(ANA_TABLES_ISDXACCESS, 0x008b4c),
> + REG(ANA_TABLES_ISDXTIDX, 0x008b50),
> + REG(ANA_TABLES_ENTRYLIM, 0x008b00),
> + REG(ANA_TABLES_PTP_ID_HIGH, 0x008b54),
> + REG(ANA_TABLES_PTP_ID_LOW, 0x008b58),
> + REG(ANA_MSTI_STATE, 0x008e00),
> + REG(ANA_PORT_VLAN_CFG, 0x007000),
> + REG(ANA_PORT_DROP_CFG, 0x007004),
> + REG(ANA_PORT_QOS_CFG, 0x007008),
> + REG(ANA_PORT_VCAP_CFG, 0x00700c),
> + REG(ANA_PORT_VCAP_S1_KEY_CFG, 0x007010),
> + REG(ANA_PORT_VCAP_S2_CFG, 0x00701c),
> + REG(ANA_PORT_PCP_DEI_MAP, 0x007020),
> + REG(ANA_PORT_CPU_FWD_CFG, 0x007060),
> + REG(ANA_PORT_CPU_FWD_BPDU_CFG, 0x007064),
> + REG(ANA_PORT_CPU_FWD_GARP_CFG, 0x007068),
> + REG(ANA_PORT_CPU_FWD_CCM_CFG, 0x00706c),
> + REG(ANA_PORT_PORT_CFG, 0x007070),
> + REG(ANA_PORT_POL_CFG, 0x007074),
> + REG(ANA_PORT_PTP_CFG, 0x007078),
> + REG(ANA_PORT_PTP_DLY1_CFG, 0x00707c),
> + REG(ANA_OAM_UPM_LM_CNT, 0x007c00),
> + REG(ANA_PORT_PTP_DLY2_CFG, 0x007080),
> + REG(ANA_PFC_PFC_CFG, 0x008800),
> + REG(ANA_PFC_PFC_TIMER, 0x008804),
> + REG(ANA_IPT_OAM_MEP_CFG, 0x008000),
> + REG(ANA_IPT_IPT, 0x008004),
> + REG(ANA_PPT_PPT, 0x008ac0),
> + REG(ANA_FID_MAP_FID_MAP, 0x000000),
> + REG(ANA_AGGR_CFG, 0x0090b4),
> + REG(ANA_CPUQ_CFG, 0x0090b8),
> + REG(ANA_CPUQ_CFG2, 0x0090bc),
> + REG(ANA_CPUQ_8021_CFG, 0x0090c0),
> + REG(ANA_DSCP_CFG, 0x009100),
> + REG(ANA_DSCP_REWR_CFG, 0x009200),
> + REG(ANA_VCAP_RNG_TYPE_CFG, 0x009240),
> + REG(ANA_VCAP_RNG_VAL_CFG, 0x009260),
> + REG(ANA_VRAP_CFG, 0x009280),
> + REG(ANA_VRAP_HDR_DATA, 0x009284),
> + REG(ANA_VRAP_HDR_MASK, 0x009288),
> + REG(ANA_DISCARD_CFG, 0x00928c),
> + REG(ANA_FID_CFG, 0x009290),
> + REG(ANA_POL_PIR_CFG, 0x004000),
> + REG(ANA_POL_CIR_CFG, 0x004004),
> + REG(ANA_POL_MODE_CFG, 0x004008),
> + REG(ANA_POL_PIR_STATE, 0x00400c),
> + REG(ANA_POL_CIR_STATE, 0x004010),
> + REG(ANA_POL_STATE, 0x004014),
> + REG(ANA_POL_FLOWC, 0x008b80),
> + REG(ANA_POL_HYST, 0x008bec),
> + REG(ANA_POL_MISC_CFG, 0x008bf0),
> +};
> +EXPORT_SYMBOL(ocelot_ana_regmap);
> +
> +const u32 ocelot_qs_regmap[] = {
> + REG(QS_XTR_GRP_CFG, 0x000000),
> + REG(QS_XTR_RD, 0x000008),
> + REG(QS_XTR_FRM_PRUNING, 0x000010),
> + REG(QS_XTR_FLUSH, 0x000018),
> + REG(QS_XTR_DATA_PRESENT, 0x00001c),
> + REG(QS_XTR_CFG, 0x000020),
> + REG(QS_INJ_GRP_CFG, 0x000024),
> + REG(QS_INJ_WR, 0x00002c),
> + REG(QS_INJ_CTRL, 0x000034),
> + REG(QS_INJ_STATUS, 0x00003c),
> + REG(QS_INJ_ERR, 0x000040),
> + REG(QS_INH_DBG, 0x000048),
> +};
> +EXPORT_SYMBOL(ocelot_qs_regmap);
> +
> +const u32 ocelot_qsys_regmap[] = {
> + REG(QSYS_PORT_MODE, 0x011200),
> + REG(QSYS_SWITCH_PORT_MODE, 0x011234),
> + REG(QSYS_STAT_CNT_CFG, 0x011264),
> + REG(QSYS_EEE_CFG, 0x011268),
> + REG(QSYS_EEE_THRES, 0x011294),
> + REG(QSYS_IGR_NO_SHARING, 0x011298),
> + REG(QSYS_EGR_NO_SHARING, 0x01129c),
> + REG(QSYS_SW_STATUS, 0x0112a0),
> + REG(QSYS_EXT_CPU_CFG, 0x0112d0),
> + REG(QSYS_PAD_CFG, 0x0112d4),
> + REG(QSYS_CPU_GROUP_MAP, 0x0112d8),
> + REG(QSYS_QMAP, 0x0112dc),
> + REG(QSYS_ISDX_SGRP, 0x011400),
> + REG(QSYS_TIMED_FRAME_ENTRY, 0x014000),
> + REG(QSYS_TFRM_MISC, 0x011310),
> + REG(QSYS_TFRM_PORT_DLY, 0x011314),
> + REG(QSYS_TFRM_TIMER_CFG_1, 0x011318),
> + REG(QSYS_TFRM_TIMER_CFG_2, 0x01131c),
> + REG(QSYS_TFRM_TIMER_CFG_3, 0x011320),
> + REG(QSYS_TFRM_TIMER_CFG_4, 0x011324),
> + REG(QSYS_TFRM_TIMER_CFG_5, 0x011328),
> + REG(QSYS_TFRM_TIMER_CFG_6, 0x01132c),
> + REG(QSYS_TFRM_TIMER_CFG_7, 0x011330),
> + REG(QSYS_TFRM_TIMER_CFG_8, 0x011334),
> + REG(QSYS_RED_PROFILE, 0x011338),
> + REG(QSYS_RES_QOS_MODE, 0x011378),
> + REG(QSYS_RES_CFG, 0x012000),
> + REG(QSYS_RES_STAT, 0x012004),
> + REG(QSYS_EGR_DROP_MODE, 0x01137c),
> + REG(QSYS_EQ_CTRL, 0x011380),
> + REG(QSYS_EVENTS_CORE, 0x011384),
> + REG(QSYS_CIR_CFG, 0x000000),
> + REG(QSYS_EIR_CFG, 0x000004),
> + REG(QSYS_SE_CFG, 0x000008),
> + REG(QSYS_SE_DWRR_CFG, 0x00000c),
> + REG(QSYS_SE_CONNECT, 0x00003c),
> + REG(QSYS_SE_DLB_SENSE, 0x000040),
> + REG(QSYS_CIR_STATE, 0x000044),
> + REG(QSYS_EIR_STATE, 0x000048),
> + REG(QSYS_SE_STATE, 0x00004c),
> + REG(QSYS_HSCH_MISC_CFG, 0x011388),
> +};
> +EXPORT_SYMBOL(ocelot_qsys_regmap);
> +
> +const u32 ocelot_rew_regmap[] = {
> + REG(REW_PORT_VLAN_CFG, 0x000000),
> + REG(REW_TAG_CFG, 0x000004),
> + REG(REW_PORT_CFG, 0x000008),
> + REG(REW_DSCP_CFG, 0x00000c),
> + REG(REW_PCP_DEI_QOS_MAP_CFG, 0x000010),
> + REG(REW_PTP_CFG, 0x000050),
> + REG(REW_PTP_DLY1_CFG, 0x000054),
> + REG(REW_DSCP_REMAP_DP1_CFG, 0x000690),
> + REG(REW_DSCP_REMAP_CFG, 0x000790),
> + REG(REW_STAT_CFG, 0x000890),
> + REG(REW_PPT, 0x000680),
> +};
> +EXPORT_SYMBOL(ocelot_rew_regmap);
> +
> +const u32 ocelot_sys_regmap[] = {
> + REG(SYS_COUNT_RX_OCTETS, 0x000000),
> + REG(SYS_COUNT_RX_UNICAST, 0x000004),
> + REG(SYS_COUNT_RX_MULTICAST, 0x000008),
> + REG(SYS_COUNT_RX_BROADCAST, 0x00000c),
> + REG(SYS_COUNT_RX_SHORTS, 0x000010),
> + REG(SYS_COUNT_RX_FRAGMENTS, 0x000014),
> + REG(SYS_COUNT_RX_JABBERS, 0x000018),
> + REG(SYS_COUNT_RX_CRC_ALIGN_ERRS, 0x00001c),
> + REG(SYS_COUNT_RX_SYM_ERRS, 0x000020),
> + REG(SYS_COUNT_RX_64, 0x000024),
> + REG(SYS_COUNT_RX_65_127, 0x000028),
> + REG(SYS_COUNT_RX_128_255, 0x00002c),
> + REG(SYS_COUNT_RX_256_1023, 0x000030),
> + REG(SYS_COUNT_RX_1024_1526, 0x000034),
> + REG(SYS_COUNT_RX_1527_MAX, 0x000038),
> + REG(SYS_COUNT_RX_PAUSE, 0x00003c),
> + REG(SYS_COUNT_RX_CONTROL, 0x000040),
> + REG(SYS_COUNT_RX_LONGS, 0x000044),
> + REG(SYS_COUNT_RX_CLASSIFIED_DROPS, 0x000048),
> + REG(SYS_COUNT_TX_OCTETS, 0x000100),
> + REG(SYS_COUNT_TX_UNICAST, 0x000104),
> + REG(SYS_COUNT_TX_MULTICAST, 0x000108),
> + REG(SYS_COUNT_TX_BROADCAST, 0x00010c),
> + REG(SYS_COUNT_TX_COLLISION, 0x000110),
> + REG(SYS_COUNT_TX_DROPS, 0x000114),
> + REG(SYS_COUNT_TX_PAUSE, 0x000118),
> + REG(SYS_COUNT_TX_64, 0x00011c),
> + REG(SYS_COUNT_TX_65_127, 0x000120),
> + REG(SYS_COUNT_TX_128_511, 0x000124),
> + REG(SYS_COUNT_TX_512_1023, 0x000128),
> + REG(SYS_COUNT_TX_1024_1526, 0x00012c),
> + REG(SYS_COUNT_TX_1527_MAX, 0x000130),
> + REG(SYS_COUNT_TX_AGING, 0x000170),
> + REG(SYS_RESET_CFG, 0x000508),
> + REG(SYS_CMID, 0x00050c),
> + REG(SYS_VLAN_ETYPE_CFG, 0x000510),
> + REG(SYS_PORT_MODE, 0x000514),
> + REG(SYS_FRONT_PORT_MODE, 0x000548),
> + REG(SYS_FRM_AGING, 0x000574),
> + REG(SYS_STAT_CFG, 0x000578),
> + REG(SYS_SW_STATUS, 0x00057c),
> + REG(SYS_MISC_CFG, 0x0005ac),
> + REG(SYS_REW_MAC_HIGH_CFG, 0x0005b0),
> + REG(SYS_REW_MAC_LOW_CFG, 0x0005dc),
> + REG(SYS_CM_ADDR, 0x000500),
> + REG(SYS_CM_DATA, 0x000504),
> + REG(SYS_PAUSE_CFG, 0x000608),
> + REG(SYS_PAUSE_TOT_CFG, 0x000638),
> + REG(SYS_ATOP, 0x00063c),
> + REG(SYS_ATOP_TOT_CFG, 0x00066c),
> + REG(SYS_MAC_FC_CFG, 0x000670),
> + REG(SYS_MMGT, 0x00069c),
> + REG(SYS_MMGT_FAST, 0x0006a0),
> + REG(SYS_EVENTS_DIF, 0x0006a4),
> + REG(SYS_EVENTS_CORE, 0x0006b4),
> + REG(SYS_CNT, 0x000000),
> + REG(SYS_PTP_STATUS, 0x0006b8),
> + REG(SYS_PTP_TXSTAMP, 0x0006bc),
> + REG(SYS_PTP_NXT, 0x0006c0),
> + REG(SYS_PTP_CFG, 0x0006c4),
> +};
> +EXPORT_SYMBOL(ocelot_sys_regmap);
> +
> +const u32 ocelot_vcap_regmap[] = {
> + /* VCAP_CORE_CFG */
> + REG(VCAP_CORE_UPDATE_CTRL, 0x000000),
> + REG(VCAP_CORE_MV_CFG, 0x000004),
> + /* VCAP_CORE_CACHE */
> + REG(VCAP_CACHE_ENTRY_DAT, 0x000008),
> + REG(VCAP_CACHE_MASK_DAT, 0x000108),
> + REG(VCAP_CACHE_ACTION_DAT, 0x000208),
> + REG(VCAP_CACHE_CNT_DAT, 0x000308),
> + REG(VCAP_CACHE_TG_DAT, 0x000388),
> + /* VCAP_CONST */
> + REG(VCAP_CONST_VCAP_VER, 0x000398),
> + REG(VCAP_CONST_ENTRY_WIDTH, 0x00039c),
> + REG(VCAP_CONST_ENTRY_CNT, 0x0003a0),
> + REG(VCAP_CONST_ENTRY_SWCNT, 0x0003a4),
> + REG(VCAP_CONST_ENTRY_TG_WIDTH, 0x0003a8),
> + REG(VCAP_CONST_ACTION_DEF_CNT, 0x0003ac),
> + REG(VCAP_CONST_ACTION_WIDTH, 0x0003b0),
> + REG(VCAP_CONST_CNT_WIDTH, 0x0003b4),
> + REG(VCAP_CONST_CORE_CNT, 0x0003b8),
> + REG(VCAP_CONST_IF_CNT, 0x0003bc),
> +};
> +EXPORT_SYMBOL(ocelot_vcap_regmap);
> +
> +const u32 ocelot_ptp_regmap[] = {
> + REG(PTP_PIN_CFG, 0x000000),
> + REG(PTP_PIN_TOD_SEC_MSB, 0x000004),
> + REG(PTP_PIN_TOD_SEC_LSB, 0x000008),
> + REG(PTP_PIN_TOD_NSEC, 0x00000c),
> + REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014),
> + REG(PTP_PIN_WF_LOW_PERIOD, 0x000018),
> + REG(PTP_CFG_MISC, 0x0000a0),
> + REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4),
> + REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8),
> +};
> +EXPORT_SYMBOL(ocelot_ptp_regmap);
> +
> +const u32 ocelot_dev_gmii_regmap[] = {
> + REG(DEV_CLOCK_CFG, 0x0),
> + REG(DEV_PORT_MISC, 0x4),
> + REG(DEV_EVENTS, 0x8),
> + REG(DEV_EEE_CFG, 0xc),
> + REG(DEV_RX_PATH_DELAY, 0x10),
> + REG(DEV_TX_PATH_DELAY, 0x14),
> + REG(DEV_PTP_PREDICT_CFG, 0x18),
> + REG(DEV_MAC_ENA_CFG, 0x1c),
> + REG(DEV_MAC_MODE_CFG, 0x20),
> + REG(DEV_MAC_MAXLEN_CFG, 0x24),
> + REG(DEV_MAC_TAGS_CFG, 0x28),
> + REG(DEV_MAC_ADV_CHK_CFG, 0x2c),
> + REG(DEV_MAC_IFG_CFG, 0x30),
> + REG(DEV_MAC_HDX_CFG, 0x34),
> + REG(DEV_MAC_DBG_CFG, 0x38),
> + REG(DEV_MAC_FC_MAC_LOW_CFG, 0x3c),
> + REG(DEV_MAC_FC_MAC_HIGH_CFG, 0x40),
> + REG(DEV_MAC_STICKY, 0x44),
> + REG(PCS1G_CFG, 0x48),
> + REG(PCS1G_MODE_CFG, 0x4c),
> + REG(PCS1G_SD_CFG, 0x50),
> + REG(PCS1G_ANEG_CFG, 0x54),
> + REG(PCS1G_ANEG_NP_CFG, 0x58),
> + REG(PCS1G_LB_CFG, 0x5c),
> + REG(PCS1G_DBG_CFG, 0x60),
> + REG(PCS1G_CDET_CFG, 0x64),
> + REG(PCS1G_ANEG_STATUS, 0x68),
> + REG(PCS1G_ANEG_NP_STATUS, 0x6c),
> + REG(PCS1G_LINK_STATUS, 0x70),
> + REG(PCS1G_LINK_DOWN_CNT, 0x74),
> + REG(PCS1G_STICKY, 0x78),
> + REG(PCS1G_DEBUG_STATUS, 0x7c),
> + REG(PCS1G_LPI_CFG, 0x80),
> + REG(PCS1G_LPI_WAKE_ERROR_CNT, 0x84),
> + REG(PCS1G_LPI_STATUS, 0x88),
> + REG(PCS1G_TSTPAT_MODE_CFG, 0x8c),
> + REG(PCS1G_TSTPAT_STATUS, 0x90),
> + REG(DEV_PCS_FX100_CFG, 0x94),
> + REG(DEV_PCS_FX100_STATUS, 0x98),
> +};
> +EXPORT_SYMBOL(ocelot_dev_gmii_regmap);
> diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
> index 4bd7e9d9ec61..ef1bf24f51b5 100644
> --- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c
> +++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
> @@ -16,303 +16,10 @@
> #include <net/switchdev.h>
>
> #include <soc/mscc/ocelot_vcap.h>
> +#include <soc/mscc/ocelot_regs.h>
> #include <soc/mscc/ocelot_hsio.h>
> #include "ocelot.h"
>
> -static const u32 ocelot_ana_regmap[] = {
> - REG(ANA_ADVLEARN, 0x009000),
> - REG(ANA_VLANMASK, 0x009004),
> - REG(ANA_PORT_B_DOMAIN, 0x009008),
> - REG(ANA_ANAGEFIL, 0x00900c),
> - REG(ANA_ANEVENTS, 0x009010),
> - REG(ANA_STORMLIMIT_BURST, 0x009014),
> - REG(ANA_STORMLIMIT_CFG, 0x009018),
> - REG(ANA_ISOLATED_PORTS, 0x009028),
> - REG(ANA_COMMUNITY_PORTS, 0x00902c),
> - REG(ANA_AUTOAGE, 0x009030),
> - REG(ANA_MACTOPTIONS, 0x009034),
> - REG(ANA_LEARNDISC, 0x009038),
> - REG(ANA_AGENCTRL, 0x00903c),
> - REG(ANA_MIRRORPORTS, 0x009040),
> - REG(ANA_EMIRRORPORTS, 0x009044),
> - REG(ANA_FLOODING, 0x009048),
> - REG(ANA_FLOODING_IPMC, 0x00904c),
> - REG(ANA_SFLOW_CFG, 0x009050),
> - REG(ANA_PORT_MODE, 0x009080),
> - REG(ANA_PGID_PGID, 0x008c00),
> - REG(ANA_TABLES_ANMOVED, 0x008b30),
> - REG(ANA_TABLES_MACHDATA, 0x008b34),
> - REG(ANA_TABLES_MACLDATA, 0x008b38),
> - REG(ANA_TABLES_MACACCESS, 0x008b3c),
> - REG(ANA_TABLES_MACTINDX, 0x008b40),
> - REG(ANA_TABLES_VLANACCESS, 0x008b44),
> - REG(ANA_TABLES_VLANTIDX, 0x008b48),
> - REG(ANA_TABLES_ISDXACCESS, 0x008b4c),
> - REG(ANA_TABLES_ISDXTIDX, 0x008b50),
> - REG(ANA_TABLES_ENTRYLIM, 0x008b00),
> - REG(ANA_TABLES_PTP_ID_HIGH, 0x008b54),
> - REG(ANA_TABLES_PTP_ID_LOW, 0x008b58),
> - REG(ANA_MSTI_STATE, 0x008e00),
> - REG(ANA_PORT_VLAN_CFG, 0x007000),
> - REG(ANA_PORT_DROP_CFG, 0x007004),
> - REG(ANA_PORT_QOS_CFG, 0x007008),
> - REG(ANA_PORT_VCAP_CFG, 0x00700c),
> - REG(ANA_PORT_VCAP_S1_KEY_CFG, 0x007010),
> - REG(ANA_PORT_VCAP_S2_CFG, 0x00701c),
> - REG(ANA_PORT_PCP_DEI_MAP, 0x007020),
> - REG(ANA_PORT_CPU_FWD_CFG, 0x007060),
> - REG(ANA_PORT_CPU_FWD_BPDU_CFG, 0x007064),
> - REG(ANA_PORT_CPU_FWD_GARP_CFG, 0x007068),
> - REG(ANA_PORT_CPU_FWD_CCM_CFG, 0x00706c),
> - REG(ANA_PORT_PORT_CFG, 0x007070),
> - REG(ANA_PORT_POL_CFG, 0x007074),
> - REG(ANA_PORT_PTP_CFG, 0x007078),
> - REG(ANA_PORT_PTP_DLY1_CFG, 0x00707c),
> - REG(ANA_OAM_UPM_LM_CNT, 0x007c00),
> - REG(ANA_PORT_PTP_DLY2_CFG, 0x007080),
> - REG(ANA_PFC_PFC_CFG, 0x008800),
> - REG(ANA_PFC_PFC_TIMER, 0x008804),
> - REG(ANA_IPT_OAM_MEP_CFG, 0x008000),
> - REG(ANA_IPT_IPT, 0x008004),
> - REG(ANA_PPT_PPT, 0x008ac0),
> - REG(ANA_FID_MAP_FID_MAP, 0x000000),
> - REG(ANA_AGGR_CFG, 0x0090b4),
> - REG(ANA_CPUQ_CFG, 0x0090b8),
> - REG(ANA_CPUQ_CFG2, 0x0090bc),
> - REG(ANA_CPUQ_8021_CFG, 0x0090c0),
> - REG(ANA_DSCP_CFG, 0x009100),
> - REG(ANA_DSCP_REWR_CFG, 0x009200),
> - REG(ANA_VCAP_RNG_TYPE_CFG, 0x009240),
> - REG(ANA_VCAP_RNG_VAL_CFG, 0x009260),
> - REG(ANA_VRAP_CFG, 0x009280),
> - REG(ANA_VRAP_HDR_DATA, 0x009284),
> - REG(ANA_VRAP_HDR_MASK, 0x009288),
> - REG(ANA_DISCARD_CFG, 0x00928c),
> - REG(ANA_FID_CFG, 0x009290),
> - REG(ANA_POL_PIR_CFG, 0x004000),
> - REG(ANA_POL_CIR_CFG, 0x004004),
> - REG(ANA_POL_MODE_CFG, 0x004008),
> - REG(ANA_POL_PIR_STATE, 0x00400c),
> - REG(ANA_POL_CIR_STATE, 0x004010),
> - REG(ANA_POL_STATE, 0x004014),
> - REG(ANA_POL_FLOWC, 0x008b80),
> - REG(ANA_POL_HYST, 0x008bec),
> - REG(ANA_POL_MISC_CFG, 0x008bf0),
> -};
> -
> -static const u32 ocelot_qs_regmap[] = {
> - REG(QS_XTR_GRP_CFG, 0x000000),
> - REG(QS_XTR_RD, 0x000008),
> - REG(QS_XTR_FRM_PRUNING, 0x000010),
> - REG(QS_XTR_FLUSH, 0x000018),
> - REG(QS_XTR_DATA_PRESENT, 0x00001c),
> - REG(QS_XTR_CFG, 0x000020),
> - REG(QS_INJ_GRP_CFG, 0x000024),
> - REG(QS_INJ_WR, 0x00002c),
> - REG(QS_INJ_CTRL, 0x000034),
> - REG(QS_INJ_STATUS, 0x00003c),
> - REG(QS_INJ_ERR, 0x000040),
> - REG(QS_INH_DBG, 0x000048),
> -};
> -
> -static const u32 ocelot_qsys_regmap[] = {
> - REG(QSYS_PORT_MODE, 0x011200),
> - REG(QSYS_SWITCH_PORT_MODE, 0x011234),
> - REG(QSYS_STAT_CNT_CFG, 0x011264),
> - REG(QSYS_EEE_CFG, 0x011268),
> - REG(QSYS_EEE_THRES, 0x011294),
> - REG(QSYS_IGR_NO_SHARING, 0x011298),
> - REG(QSYS_EGR_NO_SHARING, 0x01129c),
> - REG(QSYS_SW_STATUS, 0x0112a0),
> - REG(QSYS_EXT_CPU_CFG, 0x0112d0),
> - REG(QSYS_PAD_CFG, 0x0112d4),
> - REG(QSYS_CPU_GROUP_MAP, 0x0112d8),
> - REG(QSYS_QMAP, 0x0112dc),
> - REG(QSYS_ISDX_SGRP, 0x011400),
> - REG(QSYS_TIMED_FRAME_ENTRY, 0x014000),
> - REG(QSYS_TFRM_MISC, 0x011310),
> - REG(QSYS_TFRM_PORT_DLY, 0x011314),
> - REG(QSYS_TFRM_TIMER_CFG_1, 0x011318),
> - REG(QSYS_TFRM_TIMER_CFG_2, 0x01131c),
> - REG(QSYS_TFRM_TIMER_CFG_3, 0x011320),
> - REG(QSYS_TFRM_TIMER_CFG_4, 0x011324),
> - REG(QSYS_TFRM_TIMER_CFG_5, 0x011328),
> - REG(QSYS_TFRM_TIMER_CFG_6, 0x01132c),
> - REG(QSYS_TFRM_TIMER_CFG_7, 0x011330),
> - REG(QSYS_TFRM_TIMER_CFG_8, 0x011334),
> - REG(QSYS_RED_PROFILE, 0x011338),
> - REG(QSYS_RES_QOS_MODE, 0x011378),
> - REG(QSYS_RES_CFG, 0x012000),
> - REG(QSYS_RES_STAT, 0x012004),
> - REG(QSYS_EGR_DROP_MODE, 0x01137c),
> - REG(QSYS_EQ_CTRL, 0x011380),
> - REG(QSYS_EVENTS_CORE, 0x011384),
> - REG(QSYS_CIR_CFG, 0x000000),
> - REG(QSYS_EIR_CFG, 0x000004),
> - REG(QSYS_SE_CFG, 0x000008),
> - REG(QSYS_SE_DWRR_CFG, 0x00000c),
> - REG(QSYS_SE_CONNECT, 0x00003c),
> - REG(QSYS_SE_DLB_SENSE, 0x000040),
> - REG(QSYS_CIR_STATE, 0x000044),
> - REG(QSYS_EIR_STATE, 0x000048),
> - REG(QSYS_SE_STATE, 0x00004c),
> - REG(QSYS_HSCH_MISC_CFG, 0x011388),
> -};
> -
> -static const u32 ocelot_rew_regmap[] = {
> - REG(REW_PORT_VLAN_CFG, 0x000000),
> - REG(REW_TAG_CFG, 0x000004),
> - REG(REW_PORT_CFG, 0x000008),
> - REG(REW_DSCP_CFG, 0x00000c),
> - REG(REW_PCP_DEI_QOS_MAP_CFG, 0x000010),
> - REG(REW_PTP_CFG, 0x000050),
> - REG(REW_PTP_DLY1_CFG, 0x000054),
> - REG(REW_DSCP_REMAP_DP1_CFG, 0x000690),
> - REG(REW_DSCP_REMAP_CFG, 0x000790),
> - REG(REW_STAT_CFG, 0x000890),
> - REG(REW_PPT, 0x000680),
> -};
> -
> -static const u32 ocelot_sys_regmap[] = {
> - REG(SYS_COUNT_RX_OCTETS, 0x000000),
> - REG(SYS_COUNT_RX_UNICAST, 0x000004),
> - REG(SYS_COUNT_RX_MULTICAST, 0x000008),
> - REG(SYS_COUNT_RX_BROADCAST, 0x00000c),
> - REG(SYS_COUNT_RX_SHORTS, 0x000010),
> - REG(SYS_COUNT_RX_FRAGMENTS, 0x000014),
> - REG(SYS_COUNT_RX_JABBERS, 0x000018),
> - REG(SYS_COUNT_RX_CRC_ALIGN_ERRS, 0x00001c),
> - REG(SYS_COUNT_RX_SYM_ERRS, 0x000020),
> - REG(SYS_COUNT_RX_64, 0x000024),
> - REG(SYS_COUNT_RX_65_127, 0x000028),
> - REG(SYS_COUNT_RX_128_255, 0x00002c),
> - REG(SYS_COUNT_RX_256_1023, 0x000030),
> - REG(SYS_COUNT_RX_1024_1526, 0x000034),
> - REG(SYS_COUNT_RX_1527_MAX, 0x000038),
> - REG(SYS_COUNT_RX_PAUSE, 0x00003c),
> - REG(SYS_COUNT_RX_CONTROL, 0x000040),
> - REG(SYS_COUNT_RX_LONGS, 0x000044),
> - REG(SYS_COUNT_RX_CLASSIFIED_DROPS, 0x000048),
> - REG(SYS_COUNT_TX_OCTETS, 0x000100),
> - REG(SYS_COUNT_TX_UNICAST, 0x000104),
> - REG(SYS_COUNT_TX_MULTICAST, 0x000108),
> - REG(SYS_COUNT_TX_BROADCAST, 0x00010c),
> - REG(SYS_COUNT_TX_COLLISION, 0x000110),
> - REG(SYS_COUNT_TX_DROPS, 0x000114),
> - REG(SYS_COUNT_TX_PAUSE, 0x000118),
> - REG(SYS_COUNT_TX_64, 0x00011c),
> - REG(SYS_COUNT_TX_65_127, 0x000120),
> - REG(SYS_COUNT_TX_128_511, 0x000124),
> - REG(SYS_COUNT_TX_512_1023, 0x000128),
> - REG(SYS_COUNT_TX_1024_1526, 0x00012c),
> - REG(SYS_COUNT_TX_1527_MAX, 0x000130),
> - REG(SYS_COUNT_TX_AGING, 0x000170),
> - REG(SYS_RESET_CFG, 0x000508),
> - REG(SYS_CMID, 0x00050c),
> - REG(SYS_VLAN_ETYPE_CFG, 0x000510),
> - REG(SYS_PORT_MODE, 0x000514),
> - REG(SYS_FRONT_PORT_MODE, 0x000548),
> - REG(SYS_FRM_AGING, 0x000574),
> - REG(SYS_STAT_CFG, 0x000578),
> - REG(SYS_SW_STATUS, 0x00057c),
> - REG(SYS_MISC_CFG, 0x0005ac),
> - REG(SYS_REW_MAC_HIGH_CFG, 0x0005b0),
> - REG(SYS_REW_MAC_LOW_CFG, 0x0005dc),
> - REG(SYS_CM_ADDR, 0x000500),
> - REG(SYS_CM_DATA, 0x000504),
> - REG(SYS_PAUSE_CFG, 0x000608),
> - REG(SYS_PAUSE_TOT_CFG, 0x000638),
> - REG(SYS_ATOP, 0x00063c),
> - REG(SYS_ATOP_TOT_CFG, 0x00066c),
> - REG(SYS_MAC_FC_CFG, 0x000670),
> - REG(SYS_MMGT, 0x00069c),
> - REG(SYS_MMGT_FAST, 0x0006a0),
> - REG(SYS_EVENTS_DIF, 0x0006a4),
> - REG(SYS_EVENTS_CORE, 0x0006b4),
> - REG(SYS_CNT, 0x000000),
> - REG(SYS_PTP_STATUS, 0x0006b8),
> - REG(SYS_PTP_TXSTAMP, 0x0006bc),
> - REG(SYS_PTP_NXT, 0x0006c0),
> - REG(SYS_PTP_CFG, 0x0006c4),
> -};
> -
> -static const u32 ocelot_vcap_regmap[] = {
> - /* VCAP_CORE_CFG */
> - REG(VCAP_CORE_UPDATE_CTRL, 0x000000),
> - REG(VCAP_CORE_MV_CFG, 0x000004),
> - /* VCAP_CORE_CACHE */
> - REG(VCAP_CACHE_ENTRY_DAT, 0x000008),
> - REG(VCAP_CACHE_MASK_DAT, 0x000108),
> - REG(VCAP_CACHE_ACTION_DAT, 0x000208),
> - REG(VCAP_CACHE_CNT_DAT, 0x000308),
> - REG(VCAP_CACHE_TG_DAT, 0x000388),
> - /* VCAP_CONST */
> - REG(VCAP_CONST_VCAP_VER, 0x000398),
> - REG(VCAP_CONST_ENTRY_WIDTH, 0x00039c),
> - REG(VCAP_CONST_ENTRY_CNT, 0x0003a0),
> - REG(VCAP_CONST_ENTRY_SWCNT, 0x0003a4),
> - REG(VCAP_CONST_ENTRY_TG_WIDTH, 0x0003a8),
> - REG(VCAP_CONST_ACTION_DEF_CNT, 0x0003ac),
> - REG(VCAP_CONST_ACTION_WIDTH, 0x0003b0),
> - REG(VCAP_CONST_CNT_WIDTH, 0x0003b4),
> - REG(VCAP_CONST_CORE_CNT, 0x0003b8),
> - REG(VCAP_CONST_IF_CNT, 0x0003bc),
> -};
> -
> -static const u32 ocelot_ptp_regmap[] = {
> - REG(PTP_PIN_CFG, 0x000000),
> - REG(PTP_PIN_TOD_SEC_MSB, 0x000004),
> - REG(PTP_PIN_TOD_SEC_LSB, 0x000008),
> - REG(PTP_PIN_TOD_NSEC, 0x00000c),
> - REG(PTP_PIN_WF_HIGH_PERIOD, 0x000014),
> - REG(PTP_PIN_WF_LOW_PERIOD, 0x000018),
> - REG(PTP_CFG_MISC, 0x0000a0),
> - REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4),
> - REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8),
> -};
> -
> -static const u32 ocelot_dev_gmii_regmap[] = {
> - REG(DEV_CLOCK_CFG, 0x0),
> - REG(DEV_PORT_MISC, 0x4),
> - REG(DEV_EVENTS, 0x8),
> - REG(DEV_EEE_CFG, 0xc),
> - REG(DEV_RX_PATH_DELAY, 0x10),
> - REG(DEV_TX_PATH_DELAY, 0x14),
> - REG(DEV_PTP_PREDICT_CFG, 0x18),
> - REG(DEV_MAC_ENA_CFG, 0x1c),
> - REG(DEV_MAC_MODE_CFG, 0x20),
> - REG(DEV_MAC_MAXLEN_CFG, 0x24),
> - REG(DEV_MAC_TAGS_CFG, 0x28),
> - REG(DEV_MAC_ADV_CHK_CFG, 0x2c),
> - REG(DEV_MAC_IFG_CFG, 0x30),
> - REG(DEV_MAC_HDX_CFG, 0x34),
> - REG(DEV_MAC_DBG_CFG, 0x38),
> - REG(DEV_MAC_FC_MAC_LOW_CFG, 0x3c),
> - REG(DEV_MAC_FC_MAC_HIGH_CFG, 0x40),
> - REG(DEV_MAC_STICKY, 0x44),
> - REG(PCS1G_CFG, 0x48),
> - REG(PCS1G_MODE_CFG, 0x4c),
> - REG(PCS1G_SD_CFG, 0x50),
> - REG(PCS1G_ANEG_CFG, 0x54),
> - REG(PCS1G_ANEG_NP_CFG, 0x58),
> - REG(PCS1G_LB_CFG, 0x5c),
> - REG(PCS1G_DBG_CFG, 0x60),
> - REG(PCS1G_CDET_CFG, 0x64),
> - REG(PCS1G_ANEG_STATUS, 0x68),
> - REG(PCS1G_ANEG_NP_STATUS, 0x6c),
> - REG(PCS1G_LINK_STATUS, 0x70),
> - REG(PCS1G_LINK_DOWN_CNT, 0x74),
> - REG(PCS1G_STICKY, 0x78),
> - REG(PCS1G_DEBUG_STATUS, 0x7c),
> - REG(PCS1G_LPI_CFG, 0x80),
> - REG(PCS1G_LPI_WAKE_ERROR_CNT, 0x84),
> - REG(PCS1G_LPI_STATUS, 0x88),
> - REG(PCS1G_TSTPAT_MODE_CFG, 0x8c),
> - REG(PCS1G_TSTPAT_STATUS, 0x90),
> - REG(DEV_PCS_FX100_CFG, 0x94),
> - REG(DEV_PCS_FX100_STATUS, 0x98),
> -};
> -
> static const u32 *ocelot_regmap[TARGET_MAX] = {
> [ANA] = ocelot_ana_regmap,
> [QS] = ocelot_qs_regmap,
> diff --git a/include/soc/mscc/ocelot_regs.h b/include/soc/mscc/ocelot_regs.h
> new file mode 100644
> index 000000000000..d4508eb9e04a
> --- /dev/null
> +++ b/include/soc/mscc/ocelot_regs.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
> +/*
> + * Microsemi Ocelot Switch driver
> + *
> + * Copyright (c) 2021 Innovative Advantage Inc.
> + */
> +
> +#ifndef OCELOT_REGS_H
> +#define OCELOT_REGS_H
> +
> +extern const u32 ocelot_ana_regmap[];
> +extern const u32 ocelot_qs_regmap[];
> +extern const u32 ocelot_qsys_regmap[];
> +extern const u32 ocelot_rew_regmap[];
> +extern const u32 ocelot_sys_regmap[];
> +extern const u32 ocelot_vcap_regmap[];
> +extern const u32 ocelot_ptp_regmap[];
> +extern const u32 ocelot_dev_gmii_regmap[];
> +
> +#endif
> --
> 2.25.1
>

--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2021-08-15 19:20:14

by Colin Foster

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 09/10] net: dsa: ocelot: felix: add support for VSC75XX control over SPI

On Sat, Aug 14, 2021 at 03:02:11PM +0300, Vladimir Oltean wrote:
> On Sat, Aug 14, 2021 at 02:43:29PM +0300, Vladimir Oltean wrote:
> > The issue is that the registers for the PCS1G block look nothing like
> > the MDIO clause 22 layout, so anything that tries to map the struct
> > ocelot_pcs over a struct mdio_device is going to look like a horrible
> > shoehorn.
> >
> > For that we might need Russell's assistance.
> >
> > The documentation is at:
> > http://ww1.microchip.com/downloads/en/DeviceDoc/VMDS-10489.pdf
> > search for "Information about the registers for this product is available in the attached file."
> > and then open the PDF embedded within the PDF.
>
> In fact I do notice now that as long as you don't use any of the
> optional phylink_mii_c22_pcs_* helpers in your PCS driver, then
> struct phylink_pcs has pretty much zero dependency on struct mdio_device,
> which means that I'm wrong and it should be completely within reach to
> write a dedicated PCS driver for this hardware.
>
> As to how to make the common felix.c work with different implementations
> of struct phylink_pcs, one thing that certainly has to change is that
> struct felix should hold a struct phylink_pcs **pcs and not a
> struct lynx_pcs **pcs.
>
> Does this mean that we should refactor lynx_pcs_create() to return a
> struct phylink_pcs * instead of struct lynx_pcs *, and lynx_pcs_destroy()
> to receive the struct phylink_pcs *, use container_of() and free the
> larger struct lynx_pcs *? Yes, probably.
>
> If you feel uncomfortable with this, I can try to refactor lynx_pcs to
> make it easier to accomodate a different PCS driver in felix.

I think this is pretty straightforward. That seems like the same thing
I'd done to get regmap working in this patch since my first attempt.

Should this be a new commit in this patchset or a standalone patch?

2021-08-15 20:43:50

by Colin Foster

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 09/10] net: dsa: ocelot: felix: add support for VSC75XX control over SPI

On Sat, Aug 14, 2021 at 03:02:11PM +0300, Vladimir Oltean wrote:
> On Sat, Aug 14, 2021 at 02:43:29PM +0300, Vladimir Oltean wrote:
> > The issue is that the registers for the PCS1G block look nothing like
> > the MDIO clause 22 layout, so anything that tries to map the struct
> > ocelot_pcs over a struct mdio_device is going to look like a horrible
> > shoehorn.
> >
> > For that we might need Russell's assistance.
> >
> > The documentation is at:
> > http://ww1.microchip.com/downloads/en/DeviceDoc/VMDS-10489.pdf
> > search for "Information about the registers for this product is available in the attached file."
> > and then open the PDF embedded within the PDF.
>
> In fact I do notice now that as long as you don't use any of the
> optional phylink_mii_c22_pcs_* helpers in your PCS driver, then
> struct phylink_pcs has pretty much zero dependency on struct mdio_device,
> which means that I'm wrong and it should be completely within reach to
> write a dedicated PCS driver for this hardware.
>
> As to how to make the common felix.c work with different implementations
> of struct phylink_pcs, one thing that certainly has to change is that
> struct felix should hold a struct phylink_pcs **pcs and not a
> struct lynx_pcs **pcs.
>
> Does this mean that we should refactor lynx_pcs_create() to return a
> struct phylink_pcs * instead of struct lynx_pcs *, and lynx_pcs_destroy()
> to receive the struct phylink_pcs *, use container_of() and free the
> larger struct lynx_pcs *? Yes, probably.
>
> If you feel uncomfortable with this, I can try to refactor lynx_pcs to
> make it easier to accomodate a different PCS driver in felix.

I believe I'll need to rebase this commit before I send it out to the
maintainers, but is this what you had in mind?

I also came across some curious code in Seville where it is callocing a
struct phy_device * array instead of struct lynx_pcs *. I'm not sure if
that's technically a bug or if the thought is "a pointer array is a
pointer array."

From 323d2f68447c3532dba0d85c636ea14c66aa098f Mon Sep 17 00:00:00 2001
From: Colin Foster <[email protected]>
Date: Sun, 15 Aug 2021 13:07:47 -0700
Subject: [RFC PATCH v3 net-next] net: phy: lynx: refactor Lynx PCS module to
use generic phylink_pcs

Remove references to lynx_pcs structures so drivers like the Felix DSA
can reference alternate PCS drivers.

Signed-off-by: Colin Foster <[email protected]>
---
drivers/net/dsa/ocelot/felix.h | 2 +-
drivers/net/dsa/ocelot/felix_vsc9959.c | 10 ++++-----
drivers/net/dsa/ocelot/seville_vsc9953.c | 12 +++++-----
.../net/ethernet/freescale/dpaa2/dpaa2-mac.c | 7 +++---
.../net/ethernet/freescale/dpaa2/dpaa2-mac.h | 3 +--
.../net/ethernet/freescale/enetc/enetc_pf.c | 12 +++++-----
.../net/ethernet/freescale/enetc/enetc_pf.h | 4 ++--
drivers/net/pcs/pcs-lynx.c | 22 +++++++++++++++----
include/linux/pcs-lynx.h | 9 +++-----
9 files changed, 46 insertions(+), 35 deletions(-)

diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index c872705115bc..f51e9e8064fc 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -58,7 +58,7 @@ struct felix {
const struct felix_info *info;
struct ocelot ocelot;
struct mii_bus *imdio;
- struct lynx_pcs **pcs;
+ struct phylink_pcs **pcs;
resource_size_t switch_base;
resource_size_t imdio_base;
struct dsa_8021q_context *dsa_8021q_ctx;
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
index a84129d18007..d0b3f6be360f 100644
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
@@ -1046,7 +1046,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
int rc;

felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
- sizeof(struct lynx_pcs *),
+ sizeof(struct phylink_pcs *),
GFP_KERNEL);
if (!felix->pcs) {
dev_err(dev, "failed to allocate array for PCS PHYs\n");
@@ -1095,8 +1095,8 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)

for (port = 0; port < felix->info->num_ports; port++) {
struct ocelot_port *ocelot_port = ocelot->ports[port];
+ struct phylink_pcs *phylink;
struct mdio_device *pcs;
- struct lynx_pcs *lynx;

if (dsa_is_unused_port(felix->ds, port))
continue;
@@ -1108,13 +1108,13 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
if (IS_ERR(pcs))
continue;

- lynx = lynx_pcs_create(pcs);
+ phylink = lynx_pcs_create(pcs);
if (!lynx) {
mdio_device_free(pcs);
continue;
}

- felix->pcs[port] = lynx;
+ felix->pcs[port] = phylink;

dev_info(dev, "Found PCS at internal MDIO address %d\n", port);
}
@@ -1128,7 +1128,7 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
int port;

for (port = 0; port < ocelot->num_phys_ports; port++) {
- struct lynx_pcs *pcs = felix->pcs[port];
+ struct phylink_pcs *pcs = felix->pcs[port];

if (!pcs)
continue;
diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c
index 540cf5bc9c54..8200cc5dd24d 100644
--- a/drivers/net/dsa/ocelot/seville_vsc9953.c
+++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
@@ -1007,7 +1007,7 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
int rc;

felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
- sizeof(struct phy_device *),
+ sizeof(struct phylink_pcs *),
GFP_KERNEL);
if (!felix->pcs) {
dev_err(dev, "failed to allocate array for PCS PHYs\n");
@@ -1029,8 +1029,8 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
for (port = 0; port < felix->info->num_ports; port++) {
struct ocelot_port *ocelot_port = ocelot->ports[port];
int addr = port + 4;
+ struct phylink_pcs *phylink;
struct mdio_device *pcs;
- struct lynx_pcs *lynx;

if (dsa_is_unused_port(felix->ds, port))
continue;
@@ -1042,13 +1042,13 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
if (IS_ERR(pcs))
continue;

- lynx = lynx_pcs_create(pcs);
+ phylink = lynx_pcs_create(pcs);
if (!lynx) {
mdio_device_free(pcs);
continue;
}

- felix->pcs[port] = lynx;
+ felix->pcs[port] = phylink;

dev_info(dev, "Found PCS at internal MDIO address %d\n", addr);
}
@@ -1062,12 +1062,12 @@ static void vsc9953_mdio_bus_free(struct ocelot *ocelot)
int port;

for (port = 0; port < ocelot->num_phys_ports; port++) {
- struct lynx_pcs *pcs = felix->pcs[port];
+ struct phylink_pcs *pcs = felix->pcs[port];

if (!pcs)
continue;

- mdio_device_free(pcs->mdio);
+ mdio_device_free(lynx_pcs_get_mdio(pcs));
lynx_pcs_destroy(pcs);
}
felix_mdio_bus_free(ocelot);
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
index ccaf7e35abeb..484f0d4efefe 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
@@ -270,10 +270,11 @@ static int dpaa2_pcs_create(struct dpaa2_mac *mac,

static void dpaa2_pcs_destroy(struct dpaa2_mac *mac)
{
- struct lynx_pcs *pcs = mac->pcs;
+ struct phylink_pcs *pcs = mac->pcs;

if (pcs) {
- struct device *dev = &pcs->mdio->dev;
+ struct mdio_device *mdio = lynx_get_mdio_device(pcs);
+ struct device *dev = &mdio->dev;
lynx_pcs_destroy(pcs);
put_device(dev);
mac->pcs = NULL;
@@ -336,7 +337,7 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
mac->phylink = phylink;

if (mac->pcs)
- phylink_set_pcs(mac->phylink, &mac->pcs->pcs);
+ phylink_set_pcs(mac->phylink, mac->pcs);

err = phylink_of_phy_connect(mac->phylink, dpmac_node, 0);
if (err) {
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
index 13d42dd58ec9..d1d22b52a960 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h
@@ -7,7 +7,6 @@
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/phylink.h>
-#include <linux/pcs-lynx.h>

#include "dpmac.h"
#include "dpmac-cmd.h"
@@ -23,7 +22,7 @@ struct dpaa2_mac {
struct phylink *phylink;
phy_interface_t if_mode;
enum dpmac_link_type if_link_type;
- struct lynx_pcs *pcs;
+ struct phylink_pcs *pcs;
};

bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 31274325159a..cc2ca51ac984 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -823,7 +823,7 @@ static int enetc_imdio_create(struct enetc_pf *pf)
{
struct device *dev = &pf->si->pdev->dev;
struct enetc_mdio_priv *mdio_priv;
- struct lynx_pcs *pcs_lynx;
+ struct phylink_pcs *pcs_phylink;
struct mdio_device *pcs;
struct mii_bus *bus;
int err;
@@ -855,8 +855,8 @@ static int enetc_imdio_create(struct enetc_pf *pf)
goto unregister_mdiobus;
}

- pcs_lynx = lynx_pcs_create(pcs);
- if (!pcs_lynx) {
+ pcs_phylink = lynx_pcs_create(pcs);
+ if (!pcs_phylink) {
mdio_device_free(pcs);
err = -ENOMEM;
dev_err(dev, "cannot create lynx pcs (%d)\n", err);
@@ -864,7 +864,7 @@ static int enetc_imdio_create(struct enetc_pf *pf)
}

pf->imdio = bus;
- pf->pcs = pcs_lynx;
+ pf->pcs = pcs_phylink;

return 0;

@@ -878,7 +878,7 @@ static int enetc_imdio_create(struct enetc_pf *pf)
static void enetc_imdio_remove(struct enetc_pf *pf)
{
if (pf->pcs) {
- mdio_device_free(pf->pcs->mdio);
+ mdio_device_free(lynx_get_mdio_device(pf->pcs));
lynx_pcs_destroy(pf->pcs);
}
if (pf->imdio) {
@@ -977,7 +977,7 @@ static void enetc_pl_mac_config(struct phylink_config *config,

priv = netdev_priv(pf->si->ndev);
if (pf->pcs)
- phylink_set_pcs(priv->phylink, &pf->pcs->pcs);
+ phylink_set_pcs(priv->phylink, &pf->pcs);
}

static void enetc_force_rgmii_mac(struct enetc_hw *hw, int speed, int duplex)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 263946c51e37..c26bd66e4597 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -2,7 +2,7 @@
/* Copyright 2017-2019 NXP */

#include "enetc.h"
-#include <linux/pcs-lynx.h>
+#include <linux/phylink.h>

#define ENETC_PF_NUM_RINGS 8

@@ -46,7 +46,7 @@ struct enetc_pf {

struct mii_bus *mdio; /* saved for cleanup */
struct mii_bus *imdio;
- struct lynx_pcs *pcs;
+ struct phylink_pcs *pcs;

phy_interface_t if_mode;
struct phylink_config phylink_config;
diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c
index af36cd647bf5..bdefcb36e913 100644
--- a/drivers/net/pcs/pcs-lynx.c
+++ b/drivers/net/pcs/pcs-lynx.c
@@ -22,6 +22,11 @@
#define IF_MODE_SPEED_MSK GENMASK(3, 2)
#define IF_MODE_HALF_DUPLEX BIT(4)

+struct lynx_pcs {
+ struct phylink_pcs pcs;
+ struct mdio_device *mdio;
+};
+
enum sgmii_speed {
SGMII_SPEED_10 = 0,
SGMII_SPEED_100 = 1,
@@ -30,6 +35,15 @@ enum sgmii_speed {
};

#define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs)
+#define lynx_to_phylink_pcs(lynx) (&lynx->pcs)
+
+struct mdio_device *lynx_get_mdio_device(struct phylink_pcs *pcs)
+{
+ struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);
+
+ return lynx->mdio;
+}
+EXPORT_SYMBOL(lynx_get_mdio_device);

static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs,
struct phylink_link_state *state)
@@ -329,7 +343,7 @@ static const struct phylink_pcs_ops lynx_pcs_phylink_ops = {
.pcs_link_up = lynx_pcs_link_up,
};

-struct lynx_pcs *lynx_pcs_create(struct mdio_device *mdio)
+struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio)
{
struct lynx_pcs *lynx_pcs;

@@ -341,13 +355,13 @@ struct lynx_pcs *lynx_pcs_create(struct mdio_device *mdio)
lynx_pcs->pcs.ops = &lynx_pcs_phylink_ops;
lynx_pcs->pcs.poll = true;

- return lynx_pcs;
+ return lynx_to_phylink_pcs(lynx_pcs);
}
EXPORT_SYMBOL(lynx_pcs_create);

-void lynx_pcs_destroy(struct lynx_pcs *pcs)
+void lynx_pcs_destroy(struct phylink_pcs *pcs)
{
- kfree(pcs);
+ kfree(phylink_pcs_to_lynx(pcs));
}
EXPORT_SYMBOL(lynx_pcs_destroy);

diff --git a/include/linux/pcs-lynx.h b/include/linux/pcs-lynx.h
index a6440d6ebe95..5712cc2ce775 100644
--- a/include/linux/pcs-lynx.h
+++ b/include/linux/pcs-lynx.h
@@ -9,13 +9,10 @@
#include <linux/mdio.h>
#include <linux/phylink.h>

-struct lynx_pcs {
- struct phylink_pcs pcs;
- struct mdio_device *mdio;
-};
+struct mdio_device *lynx_get_mdio_device(struct phylink_pcs *pcs);

-struct lynx_pcs *lynx_pcs_create(struct mdio_device *mdio);
+struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio);

-void lynx_pcs_destroy(struct lynx_pcs *pcs);
+void lynx_pcs_destroy(struct phylink_pcs *pcs);

#endif /* __LINUX_PCS_LYNX_H */
--
2.25.1

2021-08-15 21:37:57

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 09/10] net: dsa: ocelot: felix: add support for VSC75XX control over SPI

On Sat, Aug 14, 2021 at 03:02:11PM +0300, Vladimir Oltean wrote:
> In fact I do notice now that as long as you don't use any of the
> optional phylink_mii_c22_pcs_* helpers in your PCS driver, then
> struct phylink_pcs has pretty much zero dependency on struct mdio_device,
> which means that I'm wrong and it should be completely within reach to
> write a dedicated PCS driver for this hardware.

Yes, this was one of the design goals when I created phylink_pcs, as I
have exactly this situation with my hardware - PCS that do not have a
MDIO interface and do not conform to MDIO register layouts. So, I
explicitly ensured that phylink_pcs, just like the rest of phylink,
is not tied to any particular model of how hardware should look like.

Glad to see that this design decision is coming in handy for other
people now. :)

--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

2021-08-15 23:18:10

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 09/10] net: dsa: ocelot: felix: add support for VSC75XX control over SPI

On Sun, Aug 15, 2021 at 01:41:49PM -0700, Colin Foster wrote:
> I also came across some curious code in Seville where it is callocing a
> struct phy_device * array instead of struct lynx_pcs *. I'm not sure if
> that's technically a bug or if the thought is "a pointer array is a
> pointer array."

I won't comment on that, but a few things I spotted in the patch:

> diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
> index a84129d18007..d0b3f6be360f 100644
> --- a/drivers/net/dsa/ocelot/felix_vsc9959.c
> +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
> @@ -1046,7 +1046,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
> int rc;
>
> felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
> - sizeof(struct lynx_pcs *),
> + sizeof(struct phylink_pcs *),
> GFP_KERNEL);
> if (!felix->pcs) {
> dev_err(dev, "failed to allocate array for PCS PHYs\n");
> @@ -1095,8 +1095,8 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
>
> for (port = 0; port < felix->info->num_ports; port++) {
> struct ocelot_port *ocelot_port = ocelot->ports[port];
> + struct phylink_pcs *phylink;
> struct mdio_device *pcs;
> - struct lynx_pcs *lynx;

Normally, "phylink" is used to refer to the main phylink data
structure, so I'm not too thrilled to see it getting re-used for the
PCS. However, as you have a variable called "pcs" already, I suppose
you don't have much choice.

That said, it would be nice to have consistent naming through at
least a single file, and you do have "pcs" below to refer to this
same thing.

Maybe using plpcs or ppcs would suffice? Or maybe use the "long name"
of phylink_pcs ?

>
> if (dsa_is_unused_port(felix->ds, port))
> continue;
> @@ -1108,13 +1108,13 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
> if (IS_ERR(pcs))
> continue;
>
> - lynx = lynx_pcs_create(pcs);
> + phylink = lynx_pcs_create(pcs);
> if (!lynx) {

I think you want to change this test.

> mdio_device_free(pcs);
> continue;
> }
>
> - felix->pcs[port] = lynx;
> + felix->pcs[port] = phylink;
>
> dev_info(dev, "Found PCS at internal MDIO address %d\n", port);
> }
> @@ -1128,7 +1128,7 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
> int port;
>
> for (port = 0; port < ocelot->num_phys_ports; port++) {
> - struct lynx_pcs *pcs = felix->pcs[port];
> + struct phylink_pcs *pcs = felix->pcs[port];
>
> if (!pcs)
> continue;
> diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c
> index 540cf5bc9c54..8200cc5dd24d 100644
> --- a/drivers/net/dsa/ocelot/seville_vsc9953.c
> +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
> @@ -1007,7 +1007,7 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
> int rc;
>
> felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
> - sizeof(struct phy_device *),
> + sizeof(struct phylink_pcs *),
> GFP_KERNEL);
> if (!felix->pcs) {
> dev_err(dev, "failed to allocate array for PCS PHYs\n");
> @@ -1029,8 +1029,8 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
> for (port = 0; port < felix->info->num_ports; port++) {
> struct ocelot_port *ocelot_port = ocelot->ports[port];
> int addr = port + 4;
> + struct phylink_pcs *phylink;
> struct mdio_device *pcs;
> - struct lynx_pcs *lynx;
>
> if (dsa_is_unused_port(felix->ds, port))
> continue;
> @@ -1042,13 +1042,13 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot)
> if (IS_ERR(pcs))
> continue;
>
> - lynx = lynx_pcs_create(pcs);
> + phylink = lynx_pcs_create(pcs);
> if (!lynx) {

Same here.

--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

2021-08-15 23:34:58

by Colin Foster

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 09/10] net: dsa: ocelot: felix: add support for VSC75XX control over SPI

On Mon, Aug 16, 2021 at 12:14:54AM +0100, Russell King (Oracle) wrote:
> > diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
> > index a84129d18007..d0b3f6be360f 100644
> > --- a/drivers/net/dsa/ocelot/felix_vsc9959.c
> > +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
> > @@ -1046,7 +1046,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
> > int rc;
> >
> > felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
> > - sizeof(struct lynx_pcs *),
> > + sizeof(struct phylink_pcs *),
> > GFP_KERNEL);
> > if (!felix->pcs) {
> > dev_err(dev, "failed to allocate array for PCS PHYs\n");
> > @@ -1095,8 +1095,8 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
> >
> > for (port = 0; port < felix->info->num_ports; port++) {
> > struct ocelot_port *ocelot_port = ocelot->ports[port];
> > + struct phylink_pcs *phylink;
> > struct mdio_device *pcs;
> > - struct lynx_pcs *lynx;
>
> Normally, "phylink" is used to refer to the main phylink data
> structure, so I'm not too thrilled to see it getting re-used for the
> PCS. However, as you have a variable called "pcs" already, I suppose
> you don't have much choice.
>
> That said, it would be nice to have consistent naming through at
> least a single file, and you do have "pcs" below to refer to this
> same thing.
>
> Maybe using plpcs or ppcs would suffice? Or maybe use the "long name"
> of phylink_pcs ?

I noticed this as well. It seems to me like the mdio_device variable
name of pcs is misleading, and perhaps should be "mdio" and phylink_pcs
should be pcs, or any of the alternatives you suggested.

>
> >
> > if (dsa_is_unused_port(felix->ds, port))
> > continue;
> > @@ -1108,13 +1108,13 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
> > if (IS_ERR(pcs))
> > continue;
> >
> > - lynx = lynx_pcs_create(pcs);
> > + phylink = lynx_pcs_create(pcs);
> > if (!lynx) {
>
> I think you want to change this test.

Yes, I caught these shortly after submitting it. Fixed.

2021-08-16 00:10:11

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 09/10] net: dsa: ocelot: felix: add support for VSC75XX control over SPI

On Sun, Aug 15, 2021 at 04:27:53PM -0700, Colin Foster wrote:
> On Mon, Aug 16, 2021 at 12:14:54AM +0100, Russell King (Oracle) wrote:
> > > diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
> > > index a84129d18007..d0b3f6be360f 100644
> > > --- a/drivers/net/dsa/ocelot/felix_vsc9959.c
> > > +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
> > > @@ -1046,7 +1046,7 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
> > > int rc;
> > >
> > > felix->pcs = devm_kcalloc(dev, felix->info->num_ports,
> > > - sizeof(struct lynx_pcs *),
> > > + sizeof(struct phylink_pcs *),
> > > GFP_KERNEL);
> > > if (!felix->pcs) {
> > > dev_err(dev, "failed to allocate array for PCS PHYs\n");
> > > @@ -1095,8 +1095,8 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot)
> > >
> > > for (port = 0; port < felix->info->num_ports; port++) {
> > > struct ocelot_port *ocelot_port = ocelot->ports[port];
> > > + struct phylink_pcs *phylink;
> > > struct mdio_device *pcs;
> > > - struct lynx_pcs *lynx;
> >
> > Normally, "phylink" is used to refer to the main phylink data
> > structure, so I'm not too thrilled to see it getting re-used for the
> > PCS. However, as you have a variable called "pcs" already, I suppose
> > you don't have much choice.
> >
> > That said, it would be nice to have consistent naming through at
> > least a single file, and you do have "pcs" below to refer to this
> > same thing.
> >
> > Maybe using plpcs or ppcs would suffice? Or maybe use the "long name"
> > of phylink_pcs ?
>
> I noticed this as well. It seems to me like the mdio_device variable
> name of pcs is misleading, and perhaps should be "mdio" and phylink_pcs
> should be pcs, or any of the alternatives you suggested.

Yes, we could alternatively could use mdiodev for mdio devices,
which would free up "pcs" for use with struct phylink_pcs.

--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

2021-08-17 09:42:43

by Vladimir Oltean

[permalink] [raw]
Subject: Re: [RFC PATCH v3 net-next 09/10] net: dsa: ocelot: felix: add support for VSC75XX control over SPI

On Sun, Aug 15, 2021 at 01:41:49PM -0700, Colin Foster wrote:
> I also came across some curious code in Seville where it is callocing a
> struct phy_device * array instead of struct lynx_pcs *. I'm not sure if
> that's technically a bug or if the thought is "a pointer array is a
> pointer array."

git blame will show you that it is a harmless leftover of commit
588d05504d2d ("net: dsa: ocelot: use the Lynx PCS helpers in Felix and
Seville"). Before that patch, the pcs was a struct phy_device.

> @@ -1062,12 +1062,12 @@ static void vsc9953_mdio_bus_free(struct ocelot *ocelot)
> int port;
>
> for (port = 0; port < ocelot->num_phys_ports; port++) {
> - struct lynx_pcs *pcs = felix->pcs[port];
> + struct phylink_pcs *pcs = felix->pcs[port];
>
> if (!pcs)
> continue;
>
> - mdio_device_free(pcs->mdio);
> + mdio_device_free(lynx_pcs_get_mdio(pcs));

Don't really have a better suggestion than lynx_pcs_get_mdio.

> lynx_pcs_destroy(pcs);
> }
> felix_mdio_bus_free(ocelot);
> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
> index ccaf7e35abeb..484f0d4efefe 100644
> --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
> +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c
> @@ -270,10 +270,11 @@ static int dpaa2_pcs_create(struct dpaa2_mac *mac,
>
> static void dpaa2_pcs_destroy(struct dpaa2_mac *mac)
> {
> - struct lynx_pcs *pcs = mac->pcs;
> + struct phylink_pcs *pcs = mac->pcs;
>
> if (pcs) {
> - struct device *dev = &pcs->mdio->dev;
> + struct mdio_device *mdio = lynx_get_mdio_device(pcs);
> + struct device *dev = &mdio->dev;
> lynx_pcs_destroy(pcs);
> put_device(dev);

Ideally dpaa2 would call mdio_device_free too, just like the others.

> mac->pcs = NULL;
> @@ -336,7 +337,7 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac)
> mac->phylink = phylink;
>
> if (mac->pcs)
> - phylink_set_pcs(mac->phylink, &mac->pcs->pcs);
> + phylink_set_pcs(mac->phylink, mac->pcs);
>
> err = phylink_of_phy_connect(mac->phylink, dpmac_node, 0);
> if (err) {
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> index 31274325159a..cc2ca51ac984 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
> @@ -823,7 +823,7 @@ static int enetc_imdio_create(struct enetc_pf *pf)
> {
> struct device *dev = &pf->si->pdev->dev;
> struct enetc_mdio_priv *mdio_priv;
> - struct lynx_pcs *pcs_lynx;
> + struct phylink_pcs *pcs_phylink;
> struct mdio_device *pcs;

Agree with Russell's suggestion to replace "pcs" with "mdiodev" wherever
it refers to a struct mdio_device. Likely as a separate patch.

> struct mii_bus *bus;
> int err;
> @@ -341,13 +355,13 @@ struct lynx_pcs *lynx_pcs_create(struct mdio_device *mdio)
> lynx_pcs->pcs.ops = &lynx_pcs_phylink_ops;
> lynx_pcs->pcs.poll = true;
>
> - return lynx_pcs;
> + return lynx_to_phylink_pcs(lynx_pcs);

I would probably write another patch to convert all occurrences of
"struct lynx_pcs" variables to the same naming scheme. Currently we have
"lynx", "pcs", "lynx_pcs" only within the pcs-lynx.c file itself. "lynx"
seems to be the predominant name so all others could be replaced with
that too.

> }
> EXPORT_SYMBOL(lynx_pcs_create);
>
> -void lynx_pcs_destroy(struct lynx_pcs *pcs)
> +void lynx_pcs_destroy(struct phylink_pcs *pcs)
> {
> - kfree(pcs);
> + kfree(phylink_pcs_to_lynx(pcs));

I would perhaps do this in two stages

struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs);

kfree(lynx);

> }
> EXPORT_SYMBOL(lynx_pcs_destroy);
>
> diff --git a/include/linux/pcs-lynx.h b/include/linux/pcs-lynx.h
> index a6440d6ebe95..5712cc2ce775 100644
> --- a/include/linux/pcs-lynx.h
> +++ b/include/linux/pcs-lynx.h
> @@ -9,13 +9,10 @@
> #include <linux/mdio.h>
> #include <linux/phylink.h>
>
> -struct lynx_pcs {
> - struct phylink_pcs pcs;
> - struct mdio_device *mdio;
> -};

Good that this structure is no longer exposed.

> +struct mdio_device *lynx_get_mdio_device(struct phylink_pcs *pcs);
>
> -struct lynx_pcs *lynx_pcs_create(struct mdio_device *mdio);
> +struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio);
>
> -void lynx_pcs_destroy(struct lynx_pcs *pcs);
> +void lynx_pcs_destroy(struct phylink_pcs *pcs);

We don't want the few phylink_pcs drivers going in different directions,
so we should modify pcs-xpcs.c too such that it no longer exposes struct
dw_xpcs to the outside world. I think I hid most of that away already,
and grepping for "xpcs->" in drivers/net/dsa and drivers/net/ethernet,
I only see xpcs->mdiodev and xpcs->pcs being accessed, so converting
khat should be a walk in the park.

Anyway, I would focus for now on getting the ocelot hardware to work and
writing the phylink_pcs driver for that. That is one part where I can't
help a lot with.