Commit 134d8368 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-ethernet-mtk_eth_soc-various-enhancements'

Daniel Golle says:

====================
net: ethernet: mtk_eth_soc: various enhancements

This series brings a variety of fixes and enhancements for mtk_eth_soc,
adds support for the MT7981 SoC and facilitates sharing the SGMII PCS
code between mtk_eth_soc and mt7530.

The whole series has been tested on MT7622+MT7531 (BPi-R64),
MT7623+MT7530 (BPi-R2), MT7981+GPY211 (GL.iNet GL-MT3000) and
MT7986+MT7531 (BPi-R3). On the BananaPi R3 a variete of SFP modules
have been tested, all of them (some SGMII with PHY, others 2500Base-X
or 1000Base-X without PHY) are working well now, however, some of them
need manually disabling of autonegotiation for the link to come up.
====================

Link: https://lore.kernel.org/r/cover.1679230025.git.daniel@makrotopia.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 56aecc0a 5b89aeae
MediaTek SGMIISYS controller
============================
The MediaTek SGMIISYS controller provides various clocks to the system.
Required Properties:
- compatible: Should be:
- "mediatek,mt7622-sgmiisys", "syscon"
- "mediatek,mt7629-sgmiisys", "syscon"
- "mediatek,mt7981-sgmiisys_0", "syscon"
- "mediatek,mt7981-sgmiisys_1", "syscon"
- "mediatek,mt7986-sgmiisys_0", "syscon"
- "mediatek,mt7986-sgmiisys_1", "syscon"
- #clock-cells: Must be 1
The SGMIISYS controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
sgmiisys: sgmiisys@1b128000 {
compatible = "mediatek,mt7622-sgmiisys", "syscon";
reg = <0 0x1b128000 0 0x1000>;
#clock-cells = <1>;
};
...@@ -21,6 +21,7 @@ properties: ...@@ -21,6 +21,7 @@ properties:
- mediatek,mt7623-eth - mediatek,mt7623-eth
- mediatek,mt7622-eth - mediatek,mt7622-eth
- mediatek,mt7629-eth - mediatek,mt7629-eth
- mediatek,mt7981-eth
- mediatek,mt7986-eth - mediatek,mt7986-eth
- ralink,rt5350-eth - ralink,rt5350-eth
...@@ -78,6 +79,11 @@ properties: ...@@ -78,6 +79,11 @@ properties:
description: description:
List of phandles to wireless ethernet dispatch nodes. List of phandles to wireless ethernet dispatch nodes.
mediatek,wed-pcie:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle to the mediatek wed-pcie controller.
dma-coherent: true dma-coherent: true
mdio-bus: mdio-bus:
...@@ -123,6 +129,8 @@ allOf: ...@@ -123,6 +129,8 @@ allOf:
mediatek,wed: false mediatek,wed: false
mediatek,wed-pcie: false
- if: - if:
properties: properties:
compatible: compatible:
...@@ -160,6 +168,8 @@ allOf: ...@@ -160,6 +168,8 @@ allOf:
description: description:
Phandle to the mediatek pcie-mirror controller. Phandle to the mediatek pcie-mirror controller.
mediatek,wed-pcie: false
- if: - if:
properties: properties:
compatible: compatible:
...@@ -206,6 +216,44 @@ allOf: ...@@ -206,6 +216,44 @@ allOf:
mediatek,wed: false mediatek,wed: false
mediatek,wed-pcie: false
- if:
properties:
compatible:
contains:
const: mediatek,mt7981-eth
then:
properties:
interrupts:
minItems: 4
clocks:
minItems: 15
maxItems: 15
clock-names:
items:
- const: fe
- const: gp2
- const: gp1
- const: wocpu0
- const: sgmii_ck
- const: sgmii_tx250m
- const: sgmii_rx250m
- const: sgmii_cdr_ref
- const: sgmii_cdr_fb
- const: sgmii2_tx250m
- const: sgmii2_rx250m
- const: sgmii2_cdr_ref
- const: sgmii2_cdr_fb
- const: netsys0
- const: netsys1
mediatek,sgmiisys:
minItems: 2
maxItems: 2
- if: - if:
properties: properties:
compatible: compatible:
...@@ -242,11 +290,6 @@ allOf: ...@@ -242,11 +290,6 @@ allOf:
minItems: 2 minItems: 2
maxItems: 2 maxItems: 2
mediatek,wed-pcie:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle to the mediatek wed-pcie controller.
patternProperties: patternProperties:
"^mac@[0-1]$": "^mac@[0-1]$":
type: object type: object
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/pcs/mediatek,sgmiisys.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek SGMIISYS Controller
maintainers:
- Matthias Brugger <matthias.bgg@gmail.com>
description:
The MediaTek SGMIISYS controller provides a SGMII PCS and some clocks
to the ethernet subsystem to which it is attached.
properties:
compatible:
items:
- enum:
- mediatek,mt7622-sgmiisys
- mediatek,mt7629-sgmiisys
- mediatek,mt7981-sgmiisys_0
- mediatek,mt7981-sgmiisys_1
- mediatek,mt7986-sgmiisys_0
- mediatek,mt7986-sgmiisys_1
- const: syscon
reg:
maxItems: 1
'#clock-cells':
const: 1
mediatek,pnswap:
description: Invert polarity of the SGMII data lanes
type: boolean
required:
- compatible
- reg
- '#clock-cells'
additionalProperties: false
examples:
- |
soc {
#address-cells = <2>;
#size-cells = <2>;
sgmiisys: syscon@1b128000 {
compatible = "mediatek,mt7622-sgmiisys", "syscon";
reg = <0 0x1b128000 0 0x1000>;
#clock-cells = <1>;
};
};
...@@ -13042,6 +13042,14 @@ L: netdev@vger.kernel.org ...@@ -13042,6 +13042,14 @@ L: netdev@vger.kernel.org
S: Maintained S: Maintained
F: drivers/net/ethernet/mediatek/ F: drivers/net/ethernet/mediatek/
MEDIATEK ETHERNET PCS DRIVER
M: Alexander Couzens <lynxis@fe80.eu>
M: Daniel Golle <daniel@makrotopia.org>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/pcs/pcs-mtk-lynxi.c
F: include/linux/pcs/pcs-mtk-lynxi.h
MEDIATEK I2C CONTROLLER DRIVER MEDIATEK I2C CONTROLLER DRIVER
M: Qii Wang <qii.wang@mediatek.com> M: Qii Wang <qii.wang@mediatek.com>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
......
...@@ -38,6 +38,7 @@ config NET_DSA_MT7530 ...@@ -38,6 +38,7 @@ config NET_DSA_MT7530
tristate "MediaTek MT7530 and MT7531 Ethernet switch support" tristate "MediaTek MT7530 and MT7531 Ethernet switch support"
select NET_DSA_TAG_MTK select NET_DSA_TAG_MTK
select MEDIATEK_GE_PHY select MEDIATEK_GE_PHY
select PCS_MTK_LYNXI
help help
This enables support for the MediaTek MT7530 and MT7531 Ethernet This enables support for the MediaTek MT7530 and MT7531 Ethernet
switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT, switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT,
......
This diff is collapsed.
...@@ -364,47 +364,8 @@ enum mt7530_vlan_port_acc_frm { ...@@ -364,47 +364,8 @@ enum mt7530_vlan_port_acc_frm {
CCR_TX_OCT_CNT_BAD) CCR_TX_OCT_CNT_BAD)
/* MT7531 SGMII register group */ /* MT7531 SGMII register group */
#define MT7531_SGMII_REG_BASE 0x5000 #define MT7531_SGMII_REG_BASE(p) (0x5000 + ((p) - 5) * 0x1000)
#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \ #define MT7531_PHYA_CTRL_SIGNAL3 0x128
((p) - 5) * 0x1000 + (r))
/* Register forSGMII PCS_CONTROL_1 */
#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(p, 0x00)
#define MT7531_SGMII_LINK_STATUS BIT(18)
#define MT7531_SGMII_AN_ENABLE BIT(12)
#define MT7531_SGMII_AN_RESTART BIT(9)
#define MT7531_SGMII_AN_COMPLETE BIT(21)
/* Register for SGMII PCS_SPPED_ABILITY */
#define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08)
#define MT7531_SGMII_TX_CONFIG_MASK GENMASK(15, 0)
#define MT7531_SGMII_TX_CONFIG BIT(0)
/* Register for SGMII_MODE */
#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(p, 0x20)
#define MT7531_SGMII_REMOTE_FAULT_DIS BIT(8)
#define MT7531_SGMII_IF_MODE_MASK GENMASK(5, 1)
#define MT7531_SGMII_FORCE_DUPLEX BIT(4)
#define MT7531_SGMII_FORCE_SPEED_MASK GENMASK(3, 2)
#define MT7531_SGMII_FORCE_SPEED_1000 BIT(3)
#define MT7531_SGMII_FORCE_SPEED_100 BIT(2)
#define MT7531_SGMII_FORCE_SPEED_10 0
#define MT7531_SGMII_SPEED_DUPLEX_AN BIT(1)
enum mt7531_sgmii_force_duplex {
MT7531_SGMII_FORCE_FULL_DUPLEX = 0,
MT7531_SGMII_FORCE_HALF_DUPLEX = 0x10,
};
/* Fields of QPHY_PWR_STATE_CTRL */
#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(p, 0xe8)
#define MT7531_SGMII_PHYA_PWD BIT(4)
/* Values of SGMII SPEED */
#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(p, 0x128)
#define MT7531_RG_TPHY_SPEED_MASK (BIT(2) | BIT(3))
#define MT7531_RG_TPHY_SPEED_1_25G 0x0
#define MT7531_RG_TPHY_SPEED_3_125G BIT(2)
/* Register for system reset */ /* Register for system reset */
#define MT7530_SYS_CTRL 0x7000 #define MT7530_SYS_CTRL 0x7000
...@@ -703,13 +664,13 @@ struct mt7530_fdb { ...@@ -703,13 +664,13 @@ struct mt7530_fdb {
* @pm: The matrix used to show all connections with the port. * @pm: The matrix used to show all connections with the port.
* @pvid: The VLAN specified is to be considered a PVID at ingress. Any * @pvid: The VLAN specified is to be considered a PVID at ingress. Any
* untagged frames will be assigned to the related VLAN. * untagged frames will be assigned to the related VLAN.
* @vlan_filtering: The flags indicating whether the port that can recognize * @sgmii_pcs: Pointer to PCS instance for SerDes ports
* VLAN-tagged frames.
*/ */
struct mt7530_port { struct mt7530_port {
bool enable; bool enable;
u32 pm; u32 pm;
u16 pvid; u16 pvid;
struct phylink_pcs *sgmii_pcs;
}; };
/* Port 5 interface select definitions */ /* Port 5 interface select definitions */
......
...@@ -19,6 +19,8 @@ config NET_MEDIATEK_SOC ...@@ -19,6 +19,8 @@ config NET_MEDIATEK_SOC
select DIMLIB select DIMLIB
select PAGE_POOL select PAGE_POOL
select PAGE_POOL_STATS select PAGE_POOL_STATS
select PCS_MTK_LYNXI
select REGMAP_MMIO
help help
This driver supports the gigabit ethernet MACs in the This driver supports the gigabit ethernet MACs in the
MediaTek SoC family. MediaTek SoC family.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# #
obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o mtk_eth-y := mtk_eth_soc.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o
mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o mtk_wed_wo.o mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o mtk_wed_wo.o
ifdef CONFIG_DEBUG_FS ifdef CONFIG_DEBUG_FS
mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o
......
...@@ -96,12 +96,20 @@ static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path) ...@@ -96,12 +96,20 @@ static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path)
static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path) static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path)
{ {
unsigned int val = 0; unsigned int val = 0, mask = 0, reg = 0;
bool updated = true; bool updated = true;
switch (path) { switch (path) {
case MTK_ETH_PATH_GMAC2_SGMII: case MTK_ETH_PATH_GMAC2_SGMII:
if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) {
reg = USB_PHY_SWITCH_REG;
val = SGMII_QPHY_SEL;
mask = QPHY_SEL_MASK;
} else {
reg = INFRA_MISC2;
val = CO_QPHY_SEL; val = CO_QPHY_SEL;
mask = val;
}
break; break;
default: default:
updated = false; updated = false;
...@@ -109,7 +117,7 @@ static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path) ...@@ -109,7 +117,7 @@ static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path)
} }
if (updated) if (updated)
regmap_update_bits(eth->infra, INFRA_MISC2, CO_QPHY_SEL, val); regmap_update_bits(eth->infra, reg, mask, val);
dev_dbg(eth->dev, "path %s in %s updated = %d\n", dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name(path), __func__, updated); mtk_eth_path_name(path), __func__, updated);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/pinctrl/devinfo.h> #include <linux/pinctrl/devinfo.h>
#include <linux/phylink.h> #include <linux/phylink.h>
#include <linux/pcs/pcs-mtk-lynxi.h>
#include <linux/jhash.h> #include <linux/jhash.h>
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <net/dsa.h> #include <net/dsa.h>
...@@ -437,7 +438,7 @@ static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config, ...@@ -437,7 +438,7 @@ static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config,
sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
0 : mac->id; 0 : mac->id;
return mtk_sgmii_select_pcs(eth->sgmii, sid); return eth->sgmii_pcs[sid];
} }
return NULL; return NULL;
...@@ -765,8 +766,10 @@ static const struct phylink_mac_ops mtk_phylink_ops = { ...@@ -765,8 +766,10 @@ static const struct phylink_mac_ops mtk_phylink_ops = {
static int mtk_mdio_init(struct mtk_eth *eth) static int mtk_mdio_init(struct mtk_eth *eth)
{ {
unsigned int max_clk = 2500000, divider;
struct device_node *mii_np; struct device_node *mii_np;
int ret; int ret;
u32 val;
mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus"); mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus");
if (!mii_np) { if (!mii_np) {
...@@ -794,6 +797,25 @@ static int mtk_mdio_init(struct mtk_eth *eth) ...@@ -794,6 +797,25 @@ static int mtk_mdio_init(struct mtk_eth *eth)
eth->mii_bus->parent = eth->dev; eth->mii_bus->parent = eth->dev;
snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np); snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np);
if (!of_property_read_u32(mii_np, "clock-frequency", &val)) {
if (val > MDC_MAX_FREQ || val < MDC_MAX_FREQ / MDC_MAX_DIVIDER) {
dev_err(eth->dev, "MDIO clock frequency out of range");
ret = -EINVAL;
goto err_put_node;
}
max_clk = val;
}
divider = min_t(unsigned int, DIV_ROUND_UP(MDC_MAX_FREQ, max_clk), 63);
/* Configure MDC Divider */
val = mtk_r32(eth, MTK_PPSC);
val &= ~PPSC_MDC_CFG;
val |= FIELD_PREP(PPSC_MDC_CFG, divider) | PPSC_MDC_TURBO;
mtk_w32(eth, val, MTK_PPSC);
dev_dbg(eth->dev, "MDC is running on %d Hz\n", MDC_MAX_FREQ / divider);
ret = of_mdiobus_register(eth->mii_bus, mii_np); ret = of_mdiobus_register(eth->mii_bus, mii_np);
err_put_node: err_put_node:
...@@ -4032,8 +4054,17 @@ static int mtk_unreg_dev(struct mtk_eth *eth) ...@@ -4032,8 +4054,17 @@ static int mtk_unreg_dev(struct mtk_eth *eth)
return 0; return 0;
} }
static void mtk_sgmii_destroy(struct mtk_eth *eth)
{
int i;
for (i = 0; i < MTK_MAX_DEVS; i++)
mtk_pcs_lynxi_destroy(eth->sgmii_pcs[i]);
}
static int mtk_cleanup(struct mtk_eth *eth) static int mtk_cleanup(struct mtk_eth *eth)
{ {
mtk_sgmii_destroy(eth);
mtk_unreg_dev(eth); mtk_unreg_dev(eth);
mtk_free_dev(eth); mtk_free_dev(eth);
cancel_work_sync(&eth->pending_work); cancel_work_sync(&eth->pending_work);
...@@ -4479,6 +4510,36 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev) ...@@ -4479,6 +4510,36 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev)
rtnl_unlock(); rtnl_unlock();
} }
static int mtk_sgmii_init(struct mtk_eth *eth)
{
struct device_node *np;
struct regmap *regmap;
u32 flags;
int i;
for (i = 0; i < MTK_MAX_DEVS; i++) {
np = of_parse_phandle(eth->dev->of_node, "mediatek,sgmiisys", i);
if (!np)
break;
regmap = syscon_node_to_regmap(np);
flags = 0;
if (of_property_read_bool(np, "mediatek,pnswap"))
flags |= MTK_SGMII_FLAG_PN_SWAP;
of_node_put(np);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
eth->sgmii_pcs[i] = mtk_pcs_lynxi_create(eth->dev, regmap,
eth->soc->ana_rgc3,
flags);
}
return 0;
}
static int mtk_probe(struct platform_device *pdev) static int mtk_probe(struct platform_device *pdev)
{ {
struct resource *res = NULL; struct resource *res = NULL;
...@@ -4542,13 +4603,7 @@ static int mtk_probe(struct platform_device *pdev) ...@@ -4542,13 +4603,7 @@ static int mtk_probe(struct platform_device *pdev)
} }
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii), err = mtk_sgmii_init(eth);
GFP_KERNEL);
if (!eth->sgmii)
return -ENOMEM;
err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node,
eth->soc->ana_rgc3);
if (err) if (err)
return err; return err;
...@@ -4559,14 +4614,17 @@ static int mtk_probe(struct platform_device *pdev) ...@@ -4559,14 +4614,17 @@ static int mtk_probe(struct platform_device *pdev)
"mediatek,pctl"); "mediatek,pctl");
if (IS_ERR(eth->pctl)) { if (IS_ERR(eth->pctl)) {
dev_err(&pdev->dev, "no pctl regmap found\n"); dev_err(&pdev->dev, "no pctl regmap found\n");
return PTR_ERR(eth->pctl); err = PTR_ERR(eth->pctl);
goto err_destroy_sgmii;
} }
} }
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res) {
return -EINVAL; err = -EINVAL;
goto err_destroy_sgmii;
}
} }
if (eth->soc->offload_version) { if (eth->soc->offload_version) {
...@@ -4676,8 +4734,8 @@ static int mtk_probe(struct platform_device *pdev) ...@@ -4676,8 +4734,8 @@ static int mtk_probe(struct platform_device *pdev)
for (i = 0; i < num_ppe; i++) { for (i = 0; i < num_ppe; i++) {
u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400; u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400;
eth->ppe[i] = mtk_ppe_init(eth, eth->base + ppe_addr, eth->ppe[i] = mtk_ppe_init(eth, eth->base + ppe_addr, i);
eth->soc->offload_version, i);
if (!eth->ppe[i]) { if (!eth->ppe[i]) {
err = -ENOMEM; err = -ENOMEM;
goto err_deinit_ppe; goto err_deinit_ppe;
...@@ -4725,6 +4783,8 @@ static int mtk_probe(struct platform_device *pdev) ...@@ -4725,6 +4783,8 @@ static int mtk_probe(struct platform_device *pdev)
mtk_hw_deinit(eth); mtk_hw_deinit(eth);
err_wed_exit: err_wed_exit:
mtk_wed_exit(); mtk_wed_exit();
err_destroy_sgmii:
mtk_sgmii_destroy(eth);
return err; return err;
} }
...@@ -4799,6 +4859,7 @@ static const struct mtk_soc_data mt7622_data = { ...@@ -4799,6 +4859,7 @@ static const struct mtk_soc_data mt7622_data = {
.required_pctl = false, .required_pctl = false,
.offload_version = 2, .offload_version = 2,
.hash_offset = 2, .hash_offset = 2,
.has_accounting = true,
.foe_entry_size = sizeof(struct mtk_foe_entry) - 16, .foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
.txrx = { .txrx = {
.txd_size = sizeof(struct mtk_tx_dma), .txd_size = sizeof(struct mtk_tx_dma),
...@@ -4836,6 +4897,7 @@ static const struct mtk_soc_data mt7629_data = { ...@@ -4836,6 +4897,7 @@ static const struct mtk_soc_data mt7629_data = {
.hw_features = MTK_HW_FEATURES, .hw_features = MTK_HW_FEATURES,
.required_clks = MT7629_CLKS_BITMAP, .required_clks = MT7629_CLKS_BITMAP,
.required_pctl = false, .required_pctl = false,
.has_accounting = true,
.txrx = { .txrx = {
.txd_size = sizeof(struct mtk_tx_dma), .txd_size = sizeof(struct mtk_tx_dma),
.rxd_size = sizeof(struct mtk_rx_dma), .rxd_size = sizeof(struct mtk_rx_dma),
...@@ -4846,6 +4908,27 @@ static const struct mtk_soc_data mt7629_data = { ...@@ -4846,6 +4908,27 @@ static const struct mtk_soc_data mt7629_data = {
}, },
}; };
static const struct mtk_soc_data mt7981_data = {
.reg_map = &mt7986_reg_map,
.ana_rgc3 = 0x128,
.caps = MT7981_CAPS,
.hw_features = MTK_HW_FEATURES,
.required_clks = MT7981_CLKS_BITMAP,
.required_pctl = false,
.offload_version = 2,
.hash_offset = 4,
.foe_entry_size = sizeof(struct mtk_foe_entry),
.has_accounting = true,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma_v2),
.rxd_size = sizeof(struct mtk_rx_dma_v2),
.rx_irq_done_mask = MTK_RX_DONE_INT_V2,
.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
.dma_len_offset = 8,
},
};
static const struct mtk_soc_data mt7986_data = { static const struct mtk_soc_data mt7986_data = {
.reg_map = &mt7986_reg_map, .reg_map = &mt7986_reg_map,
.ana_rgc3 = 0x128, .ana_rgc3 = 0x128,
...@@ -4856,6 +4939,7 @@ static const struct mtk_soc_data mt7986_data = { ...@@ -4856,6 +4939,7 @@ static const struct mtk_soc_data mt7986_data = {
.offload_version = 2, .offload_version = 2,
.hash_offset = 4, .hash_offset = 4,
.foe_entry_size = sizeof(struct mtk_foe_entry), .foe_entry_size = sizeof(struct mtk_foe_entry),
.has_accounting = true,
.txrx = { .txrx = {
.txd_size = sizeof(struct mtk_tx_dma_v2), .txd_size = sizeof(struct mtk_tx_dma_v2),
.rxd_size = sizeof(struct mtk_rx_dma_v2), .rxd_size = sizeof(struct mtk_rx_dma_v2),
...@@ -4888,6 +4972,7 @@ const struct of_device_id of_mtk_match[] = { ...@@ -4888,6 +4972,7 @@ const struct of_device_id of_mtk_match[] = {
{ .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data},
{ .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data},
{ .compatible = "mediatek,mt7629-eth", .data = &mt7629_data}, { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data},
{ .compatible = "mediatek,mt7981-eth", .data = &mt7981_data},
{ .compatible = "mediatek,mt7986-eth", .data = &mt7986_data}, { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data},
{ .compatible = "ralink,rt5350-eth", .data = &rt5350_data}, { .compatible = "ralink,rt5350-eth", .data = &rt5350_data},
{}, {},
......
...@@ -363,6 +363,13 @@ ...@@ -363,6 +363,13 @@
#define RX_DMA_VTAG_V2 BIT(0) #define RX_DMA_VTAG_V2 BIT(0)
#define RX_DMA_L4_VALID_V2 BIT(2) #define RX_DMA_L4_VALID_V2 BIT(2)
/* PHY Polling and SMI Master Control registers */
#define MTK_PPSC 0x10000
#define PPSC_MDC_CFG GENMASK(29, 24)
#define PPSC_MDC_TURBO BIT(20)
#define MDC_MAX_FREQ 25000000
#define MDC_MAX_DIVIDER 63
/* PHY Indirect Access Control registers */ /* PHY Indirect Access Control registers */
#define MTK_PHY_IAC 0x10004 #define MTK_PHY_IAC 0x10004
#define PHY_IAC_ACCESS BIT(31) #define PHY_IAC_ACCESS BIT(31)
...@@ -503,64 +510,16 @@ ...@@ -503,64 +510,16 @@
#define ETHSYS_DMA_AG_MAP_QDMA BIT(1) #define ETHSYS_DMA_AG_MAP_QDMA BIT(1)
#define ETHSYS_DMA_AG_MAP_PPE BIT(2) #define ETHSYS_DMA_AG_MAP_PPE BIT(2)
/* SGMII subsystem config registers */
/* BMCR (low 16) BMSR (high 16) */
#define SGMSYS_PCS_CONTROL_1 0x0
#define SGMII_BMCR GENMASK(15, 0)
#define SGMII_BMSR GENMASK(31, 16)
#define SGMII_AN_RESTART BIT(9)
#define SGMII_ISOLATE BIT(10)
#define SGMII_AN_ENABLE BIT(12)
#define SGMII_LINK_STATYS BIT(18)
#define SGMII_AN_ABILITY BIT(19)
#define SGMII_AN_COMPLETE BIT(21)
#define SGMII_PCS_FAULT BIT(23)
#define SGMII_AN_EXPANSION_CLR BIT(30)
#define SGMSYS_PCS_ADVERTISE 0x8
#define SGMII_ADVERTISE GENMASK(15, 0)
#define SGMII_LPA GENMASK(31, 16)
/* Register to programmable link timer, the unit in 2 * 8ns */
#define SGMSYS_PCS_LINK_TIMER 0x18
#define SGMII_LINK_TIMER_MASK GENMASK(19, 0)
#define SGMII_LINK_TIMER_DEFAULT (0x186a0 & SGMII_LINK_TIMER_MASK)
/* Register to control remote fault */
#define SGMSYS_SGMII_MODE 0x20
#define SGMII_IF_MODE_SGMII BIT(0)
#define SGMII_SPEED_DUPLEX_AN BIT(1)
#define SGMII_SPEED_MASK GENMASK(3, 2)
#define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0)
#define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1)
#define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2)
#define SGMII_DUPLEX_HALF BIT(4)
#define SGMII_IF_MODE_BIT5 BIT(5)
#define SGMII_REMOTE_FAULT_DIS BIT(8)
#define SGMII_CODE_SYNC_SET_VAL BIT(9)
#define SGMII_CODE_SYNC_SET_EN BIT(10)
#define SGMII_SEND_AN_ERROR_EN BIT(11)
#define SGMII_IF_MODE_MASK GENMASK(5, 1)
/* Register to reset SGMII design */
#define SGMII_RESERVED_0 0x34
#define SGMII_SW_RESET BIT(0)
/* Register to set SGMII speed, ANA RG_ Control Signals III*/
#define SGMSYS_ANA_RG_CS3 0x2028
#define RG_PHY_SPEED_MASK (BIT(2) | BIT(3))
#define RG_PHY_SPEED_1_25G 0x0
#define RG_PHY_SPEED_3_125G BIT(2)
/* Register to power up QPHY */
#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
#define SGMII_PHYA_PWD BIT(4)
/* Infrasys subsystem config registers */ /* Infrasys subsystem config registers */
#define INFRA_MISC2 0x70c #define INFRA_MISC2 0x70c
#define CO_QPHY_SEL BIT(0) #define CO_QPHY_SEL BIT(0)
#define GEPHY_MAC_SEL BIT(1) #define GEPHY_MAC_SEL BIT(1)
/* Top misc registers */
#define USB_PHY_SWITCH_REG 0x218
#define QPHY_SEL_MASK GENMASK(1, 0)
#define SGMII_QPHY_SEL 0x2
/* MT7628/88 specific stuff */ /* MT7628/88 specific stuff */
#define MT7628_PDMA_OFFSET 0x0800 #define MT7628_PDMA_OFFSET 0x0800
#define MT7628_SDM_OFFSET 0x0c00 #define MT7628_SDM_OFFSET 0x0c00
...@@ -741,6 +700,17 @@ enum mtk_clks_map { ...@@ -741,6 +700,17 @@ enum mtk_clks_map {
BIT(MTK_CLK_SGMII2_CDR_FB) | \ BIT(MTK_CLK_SGMII2_CDR_FB) | \
BIT(MTK_CLK_SGMII_CK) | \ BIT(MTK_CLK_SGMII_CK) | \
BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP))
#define MT7981_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \
BIT(MTK_CLK_WOCPU0) | \
BIT(MTK_CLK_SGMII_TX_250M) | \
BIT(MTK_CLK_SGMII_RX_250M) | \
BIT(MTK_CLK_SGMII_CDR_REF) | \
BIT(MTK_CLK_SGMII_CDR_FB) | \
BIT(MTK_CLK_SGMII2_TX_250M) | \
BIT(MTK_CLK_SGMII2_RX_250M) | \
BIT(MTK_CLK_SGMII2_CDR_REF) | \
BIT(MTK_CLK_SGMII2_CDR_FB) | \
BIT(MTK_CLK_SGMII_CK))
#define MT7986_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \ #define MT7986_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \
BIT(MTK_CLK_WOCPU1) | BIT(MTK_CLK_WOCPU0) | \ BIT(MTK_CLK_WOCPU1) | BIT(MTK_CLK_WOCPU0) | \
BIT(MTK_CLK_SGMII_TX_250M) | \ BIT(MTK_CLK_SGMII_TX_250M) | \
...@@ -854,6 +824,7 @@ enum mkt_eth_capabilities { ...@@ -854,6 +824,7 @@ enum mkt_eth_capabilities {
MTK_NETSYS_V2_BIT, MTK_NETSYS_V2_BIT,
MTK_SOC_MT7628_BIT, MTK_SOC_MT7628_BIT,
MTK_RSTCTRL_PPE1_BIT, MTK_RSTCTRL_PPE1_BIT,
MTK_U3_COPHY_V2_BIT,
/* MUX BITS*/ /* MUX BITS*/
MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT,
...@@ -888,6 +859,7 @@ enum mkt_eth_capabilities { ...@@ -888,6 +859,7 @@ enum mkt_eth_capabilities {
#define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) #define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT)
#define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT) #define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT)
#define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT) #define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT)
#define MTK_U3_COPHY_V2 BIT(MTK_U3_COPHY_V2_BIT)
#define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \
BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT) BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
...@@ -960,6 +932,11 @@ enum mkt_eth_capabilities { ...@@ -960,6 +932,11 @@ enum mkt_eth_capabilities {
MTK_MUX_U3_GMAC2_TO_QPHY | \ MTK_MUX_U3_GMAC2_TO_QPHY | \
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA)
#define MT7981_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \
MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1)
#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ #define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \
MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \
MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1) MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1)
...@@ -1034,6 +1011,8 @@ struct mtk_reg_map { ...@@ -1034,6 +1011,8 @@ struct mtk_reg_map {
* the extra setup for those pins used by GMAC. * the extra setup for those pins used by GMAC.
* @hash_offset Flow table hash offset. * @hash_offset Flow table hash offset.
* @foe_entry_size Foe table entry size. * @foe_entry_size Foe table entry size.
* @has_accounting Bool indicating support for accounting of
* offloaded flows.
* @txd_size Tx DMA descriptor size. * @txd_size Tx DMA descriptor size.
* @rxd_size Rx DMA descriptor size. * @rxd_size Rx DMA descriptor size.
* @rx_irq_done_mask Rx irq done register mask. * @rx_irq_done_mask Rx irq done register mask.
...@@ -1051,6 +1030,7 @@ struct mtk_soc_data { ...@@ -1051,6 +1030,7 @@ struct mtk_soc_data {
u8 hash_offset; u8 hash_offset;
u16 foe_entry_size; u16 foe_entry_size;
netdev_features_t hw_features; netdev_features_t hw_features;
bool has_accounting;
struct { struct {
u32 txd_size; u32 txd_size;
u32 rxd_size; u32 rxd_size;
...@@ -1066,29 +1046,6 @@ struct mtk_soc_data { ...@@ -1066,29 +1046,6 @@ struct mtk_soc_data {
/* currently no SoC has more than 2 macs */ /* currently no SoC has more than 2 macs */
#define MTK_MAX_DEVS 2 #define MTK_MAX_DEVS 2
/* struct mtk_pcs - This structure holds each sgmii regmap and associated
* data
* @regmap: The register map pointing at the range used to setup
* SGMII modes
* @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap
* @interface: Currently configured interface mode
* @pcs: Phylink PCS structure
*/
struct mtk_pcs {
struct regmap *regmap;
u32 ana_rgc3;
phy_interface_t interface;
struct phylink_pcs pcs;
};
/* struct mtk_sgmii - This is the structure holding sgmii regmap and its
* characteristics
* @pcs Array of individual PCS structures
*/
struct mtk_sgmii {
struct mtk_pcs pcs[MTK_MAX_DEVS];
};
/* struct mtk_eth - This is the main datasructure for holding the state /* struct mtk_eth - This is the main datasructure for holding the state
* of the driver * of the driver
* @dev: The device pointer * @dev: The device pointer
...@@ -1108,6 +1065,7 @@ struct mtk_sgmii { ...@@ -1108,6 +1065,7 @@ struct mtk_sgmii {
* MII modes * MII modes
* @infra: The register map pointing at the range used to setup * @infra: The register map pointing at the range used to setup
* SGMII and GePHY path * SGMII and GePHY path
* @sgmii_pcs: Pointers to mtk-pcs-lynxi phylink_pcs instances
* @pctl: The register map pointing at the range used to setup * @pctl: The register map pointing at the range used to setup
* GMAC port drive/slew values * GMAC port drive/slew values
* @dma_refcnt: track how many netdevs are using the DMA engine * @dma_refcnt: track how many netdevs are using the DMA engine
...@@ -1149,7 +1107,7 @@ struct mtk_eth { ...@@ -1149,7 +1107,7 @@ struct mtk_eth {
unsigned long sysclk; unsigned long sysclk;
struct regmap *ethsys; struct regmap *ethsys;
struct regmap *infra; struct regmap *infra;
struct mtk_sgmii *sgmii; struct phylink_pcs *sgmii_pcs[MTK_MAX_DEVS];
struct regmap *pctl; struct regmap *pctl;
bool hwlro; bool hwlro;
refcount_t dma_refcnt; refcount_t dma_refcnt;
...@@ -1311,10 +1269,6 @@ void mtk_stats_update_mac(struct mtk_mac *mac); ...@@ -1311,10 +1269,6 @@ void mtk_stats_update_mac(struct mtk_mac *mac);
void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
u32 mtk_r32(struct mtk_eth *eth, unsigned reg); u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id);
int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np,
u32 ana_rgc3);
int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id);
int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id);
int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id); int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id);
......
...@@ -74,6 +74,48 @@ static int mtk_ppe_wait_busy(struct mtk_ppe *ppe) ...@@ -74,6 +74,48 @@ static int mtk_ppe_wait_busy(struct mtk_ppe *ppe)
return ret; return ret;
} }
static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe)
{
int ret;
u32 val;
ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val,
!(val & MTK_PPE_MIB_SER_CR_ST),
20, MTK_PPE_WAIT_TIMEOUT_US);
if (ret)
dev_err(ppe->dev, "MIB table busy");
return ret;
}
static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets)
{
u32 byte_cnt_low, byte_cnt_high, pkt_cnt_low, pkt_cnt_high;
u32 val, cnt_r0, cnt_r1, cnt_r2;
int ret;
val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST;
ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val);
ret = mtk_ppe_mib_wait_busy(ppe);
if (ret)
return ret;
cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0);
cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1);
cnt_r2 = readl(ppe->base + MTK_PPE_MIB_SER_R2);
byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0);
byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1);
pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1);
pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2);
*bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low;
*packets = (pkt_cnt_high << 16) | pkt_cnt_low;
return 0;
}
static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) static void mtk_ppe_cache_clear(struct mtk_ppe *ppe)
{ {
ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR); ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
...@@ -458,6 +500,13 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ...@@ -458,6 +500,13 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
hwe->ib1 &= ~MTK_FOE_IB1_STATE; hwe->ib1 &= ~MTK_FOE_IB1_STATE;
hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID);
dma_wmb(); dma_wmb();
if (ppe->accounting) {
struct mtk_foe_accounting *acct;
acct = ppe->acct_table + entry->hash * sizeof(*acct);
acct->packets = 0;
acct->bytes = 0;
}
} }
entry->hash = 0xffff; entry->hash = 0xffff;
...@@ -565,6 +614,9 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, ...@@ -565,6 +614,9 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
wmb(); wmb();
hwe->ib1 = entry->ib1; hwe->ib1 = entry->ib1;
if (ppe->accounting)
*mtk_foe_entry_ib2(eth, hwe) |= MTK_FOE_IB2_MIB_CNT;
dma_wmb(); dma_wmb();
mtk_ppe_cache_clear(ppe); mtk_ppe_cache_clear(ppe);
...@@ -756,11 +808,39 @@ int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) ...@@ -756,11 +808,39 @@ int mtk_ppe_prepare_reset(struct mtk_ppe *ppe)
return mtk_ppe_wait_busy(ppe); return mtk_ppe_wait_busy(ppe);
} }
struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index,
int version, int index) struct mtk_foe_accounting *diff)
{
struct mtk_foe_accounting *acct;
int size = sizeof(struct mtk_foe_accounting);
u64 bytes, packets;
if (!ppe->accounting)
return NULL;
if (mtk_mib_entry_read(ppe, index, &bytes, &packets))
return NULL;
acct = ppe->acct_table + index * size;
acct->bytes += bytes;
acct->packets += packets;
if (diff) {
diff->bytes = bytes;
diff->packets = packets;
}
return acct;
}
struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index)
{ {
bool accounting = eth->soc->has_accounting;
const struct mtk_soc_data *soc = eth->soc; const struct mtk_soc_data *soc = eth->soc;
struct mtk_foe_accounting *acct;
struct device *dev = eth->dev; struct device *dev = eth->dev;
struct mtk_mib_entry *mib;
struct mtk_ppe *ppe; struct mtk_ppe *ppe;
u32 foe_flow_size; u32 foe_flow_size;
void *foe; void *foe;
...@@ -777,7 +857,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, ...@@ -777,7 +857,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
ppe->base = base; ppe->base = base;
ppe->eth = eth; ppe->eth = eth;
ppe->dev = dev; ppe->dev = dev;
ppe->version = version; ppe->version = eth->soc->offload_version;
ppe->accounting = accounting;
foe = dmam_alloc_coherent(ppe->dev, foe = dmam_alloc_coherent(ppe->dev,
MTK_PPE_ENTRIES * soc->foe_entry_size, MTK_PPE_ENTRIES * soc->foe_entry_size,
...@@ -793,6 +874,23 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, ...@@ -793,6 +874,23 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
if (!ppe->foe_flow) if (!ppe->foe_flow)
goto err_free_l2_flows; goto err_free_l2_flows;
if (accounting) {
mib = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*mib),
&ppe->mib_phys, GFP_KERNEL);
if (!mib)
return NULL;
ppe->mib_table = mib;
acct = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct),
GFP_KERNEL);
if (!acct)
return NULL;
ppe->acct_table = acct;
}
mtk_ppe_debugfs_init(ppe, index); mtk_ppe_debugfs_init(ppe, index);
return ppe; return ppe;
...@@ -922,6 +1020,16 @@ void mtk_ppe_start(struct mtk_ppe *ppe) ...@@ -922,6 +1020,16 @@ void mtk_ppe_start(struct mtk_ppe *ppe)
ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777); ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777);
ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f); ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f);
} }
if (ppe->accounting && ppe->mib_phys) {
ppe_w32(ppe, MTK_PPE_MIB_TB_BASE, ppe->mib_phys);
ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_EN,
MTK_PPE_MIB_CFG_EN);
ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_RD_CLR,
MTK_PPE_MIB_CFG_RD_CLR);
ppe_m32(ppe, MTK_PPE_MIB_CACHE_CTL, MTK_PPE_MIB_CACHE_CTL_EN,
MTK_PPE_MIB_CFG_RD_CLR);
}
} }
int mtk_ppe_stop(struct mtk_ppe *ppe) int mtk_ppe_stop(struct mtk_ppe *ppe)
......
...@@ -57,6 +57,7 @@ enum { ...@@ -57,6 +57,7 @@ enum {
#define MTK_FOE_IB2_MULTICAST BIT(8) #define MTK_FOE_IB2_MULTICAST BIT(8)
#define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12) #define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12)
#define MTK_FOE_IB2_MIB_CNT BIT(15)
#define MTK_FOE_IB2_WDMA_DEVIDX BIT(16) #define MTK_FOE_IB2_WDMA_DEVIDX BIT(16)
#define MTK_FOE_IB2_WDMA_WINFO BIT(17) #define MTK_FOE_IB2_WDMA_WINFO BIT(17)
...@@ -285,16 +286,34 @@ struct mtk_flow_entry { ...@@ -285,16 +286,34 @@ struct mtk_flow_entry {
unsigned long cookie; unsigned long cookie;
}; };
struct mtk_mib_entry {
u32 byt_cnt_l;
u16 byt_cnt_h;
u32 pkt_cnt_l;
u8 pkt_cnt_h;
u8 _rsv0;
u32 _rsv1;
} __packed;
struct mtk_foe_accounting {
u64 bytes;
u64 packets;
};
struct mtk_ppe { struct mtk_ppe {
struct mtk_eth *eth; struct mtk_eth *eth;
struct device *dev; struct device *dev;
void __iomem *base; void __iomem *base;
int version; int version;
char dirname[5]; char dirname[5];
bool accounting;
void *foe_table; void *foe_table;
dma_addr_t foe_phys; dma_addr_t foe_phys;
struct mtk_mib_entry *mib_table;
dma_addr_t mib_phys;
u16 foe_check_time[MTK_PPE_ENTRIES]; u16 foe_check_time[MTK_PPE_ENTRIES];
struct hlist_head *foe_flow; struct hlist_head *foe_flow;
...@@ -303,8 +322,8 @@ struct mtk_ppe { ...@@ -303,8 +322,8 @@ struct mtk_ppe {
void *acct_table; void *acct_table;
}; };
struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index);
int version, int index);
void mtk_ppe_deinit(struct mtk_eth *eth); void mtk_ppe_deinit(struct mtk_eth *eth);
void mtk_ppe_start(struct mtk_ppe *ppe); void mtk_ppe_start(struct mtk_ppe *ppe);
int mtk_ppe_stop(struct mtk_ppe *ppe); int mtk_ppe_stop(struct mtk_ppe *ppe);
...@@ -359,5 +378,7 @@ int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); ...@@ -359,5 +378,7 @@ int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index);
struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index,
struct mtk_foe_accounting *diff);
#endif #endif
...@@ -82,6 +82,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind) ...@@ -82,6 +82,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i); struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i);
struct mtk_foe_mac_info *l2; struct mtk_foe_mac_info *l2;
struct mtk_flow_addr_info ai = {}; struct mtk_flow_addr_info ai = {};
struct mtk_foe_accounting *acct;
unsigned char h_source[ETH_ALEN]; unsigned char h_source[ETH_ALEN];
unsigned char h_dest[ETH_ALEN]; unsigned char h_dest[ETH_ALEN];
int type, state; int type, state;
...@@ -95,6 +96,8 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind) ...@@ -95,6 +96,8 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
if (bind && state != MTK_FOE_STATE_BIND) if (bind && state != MTK_FOE_STATE_BIND)
continue; continue;
acct = mtk_foe_entry_get_mib(ppe, i, NULL);
type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
seq_printf(m, "%05x %s %7s", i, seq_printf(m, "%05x %s %7s", i,
mtk_foe_entry_state_str(state), mtk_foe_entry_state_str(state),
...@@ -153,9 +156,11 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind) ...@@ -153,9 +156,11 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
*((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo); *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
seq_printf(m, " eth=%pM->%pM etype=%04x" seq_printf(m, " eth=%pM->%pM etype=%04x"
" vlan=%d,%d ib1=%08x ib2=%08x\n", " vlan=%d,%d ib1=%08x ib2=%08x"
" packets=%llu bytes=%llu\n",
h_source, h_dest, ntohs(l2->etype), h_source, h_dest, ntohs(l2->etype),
l2->vlan1, l2->vlan2, entry->ib1, ib2); l2->vlan1, l2->vlan2, entry->ib1, ib2,
acct ? acct->packets : 0, acct ? acct->bytes : 0);
} }
return 0; return 0;
......
...@@ -497,6 +497,7 @@ static int ...@@ -497,6 +497,7 @@ static int
mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f) mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
{ {
struct mtk_flow_entry *entry; struct mtk_flow_entry *entry;
struct mtk_foe_accounting diff;
u32 idle; u32 idle;
entry = rhashtable_lookup(&eth->flow_table, &f->cookie, entry = rhashtable_lookup(&eth->flow_table, &f->cookie,
...@@ -507,6 +508,13 @@ mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f) ...@@ -507,6 +508,13 @@ mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry); idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry);
f->stats.lastused = jiffies - idle * HZ; f->stats.lastused = jiffies - idle * HZ;
if (entry->hash != 0xFFFF &&
mtk_foe_entry_get_mib(eth->ppe[entry->ppe_index], entry->hash,
&diff)) {
f->stats.pkts += diff.packets;
f->stats.bytes += diff.bytes;
}
return 0; return 0;
} }
......
...@@ -149,6 +149,20 @@ enum { ...@@ -149,6 +149,20 @@ enum {
#define MTK_PPE_MIB_TB_BASE 0x338 #define MTK_PPE_MIB_TB_BASE 0x338
#define MTK_PPE_MIB_SER_CR 0x33C
#define MTK_PPE_MIB_SER_CR_ST BIT(16)
#define MTK_PPE_MIB_SER_CR_ADDR GENMASK(13, 0)
#define MTK_PPE_MIB_SER_R0 0x340
#define MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW GENMASK(31, 0)
#define MTK_PPE_MIB_SER_R1 0x344
#define MTK_PPE_MIB_SER_R1_PKT_CNT_LOW GENMASK(31, 16)
#define MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH GENMASK(15, 0)
#define MTK_PPE_MIB_SER_R2 0x348
#define MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH GENMASK(23, 0)
#define MTK_PPE_MIB_CACHE_CTL 0x350 #define MTK_PPE_MIB_CACHE_CTL 0x350
#define MTK_PPE_MIB_CACHE_CTL_EN BIT(0) #define MTK_PPE_MIB_CACHE_CTL_EN BIT(0)
#define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2) #define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2)
......
...@@ -18,6 +18,13 @@ config PCS_LYNX ...@@ -18,6 +18,13 @@ config PCS_LYNX
This module provides helpers to phylink for managing the Lynx PCS This module provides helpers to phylink for managing the Lynx PCS
which is part of the Layerscape and QorIQ Ethernet SERDES. which is part of the Layerscape and QorIQ Ethernet SERDES.
config PCS_MTK_LYNXI
tristate
select REGMAP
help
This module provides helpers to phylink for managing the LynxI PCS
which is part of MediaTek's SoC and Ethernet switch ICs.
config PCS_RZN1_MIIC config PCS_RZN1_MIIC
tristate "Renesas RZ/N1 MII converter" tristate "Renesas RZ/N1 MII converter"
depends on OF && (ARCH_RZN1 || COMPILE_TEST) depends on OF && (ARCH_RZN1 || COMPILE_TEST)
......
...@@ -5,5 +5,6 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o ...@@ -5,5 +5,6 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o
obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o
obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o
obj-$(CONFIG_PCS_ALTERA_TSE) += pcs-altera-tse.o obj-$(CONFIG_PCS_ALTERA_TSE) += pcs-altera-tse.o
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018-2019 MediaTek Inc. // Copyright (c) 2018-2019 MediaTek Inc.
/* A library for MediaTek SGMII circuit /* A library for MediaTek SGMII circuit
* *
* Author: Sean Wang <sean.wang@mediatek.com> * Author: Sean Wang <sean.wang@mediatek.com>
* Author: Alexander Couzens <lynxis@fe80.eu>
* Author: Daniel Golle <daniel@makrotopia.org>
* *
*/ */
#include <linux/mfd/syscon.h> #include <linux/mdio.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/pcs/pcs-mtk-lynxi.h>
#include <linux/phylink.h> #include <linux/phylink.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include "mtk_eth_soc.h" /* SGMII subsystem config registers */
/* BMCR (low 16) BMSR (high 16) */
#define SGMSYS_PCS_CONTROL_1 0x0
#define SGMII_BMCR GENMASK(15, 0)
#define SGMII_BMSR GENMASK(31, 16)
#define SGMSYS_PCS_DEVICE_ID 0x4
#define SGMII_LYNXI_DEV_ID 0x4d544950
#define SGMSYS_PCS_ADVERTISE 0x8
#define SGMII_ADVERTISE GENMASK(15, 0)
#define SGMII_LPA GENMASK(31, 16)
#define SGMSYS_PCS_SCRATCH 0x14
#define SGMII_DEV_VERSION GENMASK(31, 16)
/* Register to programmable link timer, the unit in 2 * 8ns */
#define SGMSYS_PCS_LINK_TIMER 0x18
#define SGMII_LINK_TIMER_MASK GENMASK(19, 0)
#define SGMII_LINK_TIMER_VAL(ns) FIELD_PREP(SGMII_LINK_TIMER_MASK, \
((ns) / 2 / 8))
/* Register to control remote fault */
#define SGMSYS_SGMII_MODE 0x20
#define SGMII_IF_MODE_SGMII BIT(0)
#define SGMII_SPEED_DUPLEX_AN BIT(1)
#define SGMII_SPEED_MASK GENMASK(3, 2)
#define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0)
#define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1)
#define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2)
#define SGMII_DUPLEX_HALF BIT(4)
#define SGMII_REMOTE_FAULT_DIS BIT(8)
/* Register to reset SGMII design */
#define SGMSYS_RESERVED_0 0x34
#define SGMII_SW_RESET BIT(0)
/* Register to set SGMII speed, ANA RG_ Control Signals III */
#define SGMII_PHY_SPEED_MASK GENMASK(3, 2)
#define SGMII_PHY_SPEED_1_25G FIELD_PREP(SGMII_PHY_SPEED_MASK, 0)
#define SGMII_PHY_SPEED_3_125G FIELD_PREP(SGMII_PHY_SPEED_MASK, 1)
/* Register to power up QPHY */
#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
#define SGMII_PHYA_PWD BIT(4)
/* Register to QPHY wrapper control */
#define SGMSYS_QPHY_WRAP_CTRL 0xec
#define SGMII_PN_SWAP_MASK GENMASK(1, 0)
#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1))
/* struct mtk_pcs_lynxi - This structure holds each sgmii regmap andassociated
* data
* @regmap: The register map pointing at the range used to setup
* SGMII modes
* @dev: Pointer to device owning the PCS
* @ana_rgc3: The offset of register ANA_RGC3 relative to regmap
* @interface: Currently configured interface mode
* @pcs: Phylink PCS structure
* @flags: Flags indicating hardware properties
*/
struct mtk_pcs_lynxi {
struct regmap *regmap;
u32 ana_rgc3;
phy_interface_t interface;
struct phylink_pcs pcs;
u32 flags;
};
static struct mtk_pcs *pcs_to_mtk_pcs(struct phylink_pcs *pcs) static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs)
{ {
return container_of(pcs, struct mtk_pcs, pcs); return container_of(pcs, struct mtk_pcs_lynxi, pcs);
} }
static void mtk_pcs_get_state(struct phylink_pcs *pcs, static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs,
struct phylink_link_state *state) struct phylink_link_state *state)
{ {
struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
unsigned int bm, adv; unsigned int bm, adv;
/* Read the BMSR and LPA */ /* Read the BMSR and LPA */
...@@ -33,13 +102,13 @@ static void mtk_pcs_get_state(struct phylink_pcs *pcs, ...@@ -33,13 +102,13 @@ static void mtk_pcs_get_state(struct phylink_pcs *pcs,
FIELD_GET(SGMII_LPA, adv)); FIELD_GET(SGMII_LPA, adv));
} }
static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int mode,
phy_interface_t interface, phy_interface_t interface,
const unsigned long *advertising, const unsigned long *advertising,
bool permit_pause_to_mac) bool permit_pause_to_mac)
{ {
struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
bool mode_changed = false, changed, use_an; bool mode_changed = false, changed, use_an;
struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
unsigned int rgc3, sgm_mode, bmcr; unsigned int rgc3, sgm_mode, bmcr;
int advertise, link_timer; int advertise, link_timer;
...@@ -72,11 +141,10 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, ...@@ -72,11 +141,10 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
use_an = false; use_an = false;
} }
if (use_an) { if (use_an)
bmcr = SGMII_AN_ENABLE; bmcr = BMCR_ANENABLE;
} else { else
bmcr = 0; bmcr = 0;
}
if (mpcs->interface != interface) { if (mpcs->interface != interface) {
link_timer = phylink_get_link_timer_ns(interface); link_timer = phylink_get_link_timer_ns(interface);
...@@ -84,24 +152,30 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, ...@@ -84,24 +152,30 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
return link_timer; return link_timer;
/* PHYA power down */ /* PHYA power down */
regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
SGMII_PHYA_PWD, SGMII_PHYA_PWD); SGMII_PHYA_PWD);
/* Reset SGMII PCS state */ /* Reset SGMII PCS state */
regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0, regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0,
SGMII_SW_RESET, SGMII_SW_RESET); SGMII_SW_RESET);
if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP)
regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
SGMII_PN_SWAP_MASK,
SGMII_PN_SWAP_TX_RX);
if (interface == PHY_INTERFACE_MODE_2500BASEX) if (interface == PHY_INTERFACE_MODE_2500BASEX)
rgc3 = RG_PHY_SPEED_3_125G; rgc3 = SGMII_PHY_SPEED_3_125G;
else else
rgc3 = 0; rgc3 = SGMII_PHY_SPEED_1_25G;
/* Configure the underlying interface speed */ /* Configure the underlying interface speed */
regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3,
RG_PHY_SPEED_3_125G, rgc3); SGMII_PHY_SPEED_MASK, rgc3);
/* Setup the link timer */ /* Setup the link timer */
regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
SGMII_LINK_TIMER_VAL(link_timer));
mpcs->interface = interface; mpcs->interface = interface;
mode_changed = true; mode_changed = true;
...@@ -118,7 +192,7 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, ...@@ -118,7 +192,7 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
/* Update the BMCR */ /* Update the BMCR */
regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1,
SGMII_AN_ENABLE, bmcr); BMCR_ANENABLE, bmcr);
/* Release PHYA power down state /* Release PHYA power down state
* Only removing bit SGMII_PHYA_PWD isn't enough. * Only removing bit SGMII_PHYA_PWD isn't enough.
...@@ -135,18 +209,18 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, ...@@ -135,18 +209,18 @@ static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
return changed || mode_changed; return changed || mode_changed;
} }
static void mtk_pcs_restart_an(struct phylink_pcs *pcs) static void mtk_pcs_lynxi_restart_an(struct phylink_pcs *pcs)
{ {
struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, regmap_set_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, BMCR_ANRESTART);
SGMII_AN_RESTART, SGMII_AN_RESTART);
} }
static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs, unsigned int mode,
phy_interface_t interface, int speed, int duplex) phy_interface_t interface, int speed,
int duplex)
{ {
struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
unsigned int sgm_mode; unsigned int sgm_mode;
if (!phylink_autoneg_inband(mode)) { if (!phylink_autoneg_inband(mode)) {
...@@ -167,41 +241,65 @@ static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, ...@@ -167,41 +241,65 @@ static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
} }
} }
static const struct phylink_pcs_ops mtk_pcs_ops = { static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = {
.pcs_get_state = mtk_pcs_get_state, .pcs_get_state = mtk_pcs_lynxi_get_state,
.pcs_config = mtk_pcs_config, .pcs_config = mtk_pcs_lynxi_config,
.pcs_an_restart = mtk_pcs_restart_an, .pcs_an_restart = mtk_pcs_lynxi_restart_an,
.pcs_link_up = mtk_pcs_link_up, .pcs_link_up = mtk_pcs_lynxi_link_up,
}; };
int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
struct regmap *regmap, u32 ana_rgc3,
u32 flags)
{ {
struct device_node *np; struct mtk_pcs_lynxi *mpcs;
int i; u32 id, ver;
int ret;
for (i = 0; i < MTK_MAX_DEVS; i++) {
np = of_parse_phandle(r, "mediatek,sgmiisys", i); ret = regmap_read(regmap, SGMSYS_PCS_DEVICE_ID, &id);
if (!np) if (ret < 0)
break; return NULL;
ss->pcs[i].ana_rgc3 = ana_rgc3; if (id != SGMII_LYNXI_DEV_ID) {
ss->pcs[i].regmap = syscon_node_to_regmap(np); dev_err(dev, "unknown PCS device id %08x\n", id);
of_node_put(np); return NULL;
if (IS_ERR(ss->pcs[i].regmap))
return PTR_ERR(ss->pcs[i].regmap);
ss->pcs[i].pcs.ops = &mtk_pcs_ops;
ss->pcs[i].pcs.poll = true;
ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
} }
return 0; ret = regmap_read(regmap, SGMSYS_PCS_SCRATCH, &ver);
if (ret < 0)
return NULL;
ver = FIELD_GET(SGMII_DEV_VERSION, ver);
if (ver != 0x1) {
dev_err(dev, "unknown PCS device version %04x\n", ver);
return NULL;
}
dev_dbg(dev, "MediaTek LynxI SGMII PCS (id 0x%08x, ver 0x%04x)\n", id,
ver);
mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
if (!mpcs)
return NULL;
mpcs->ana_rgc3 = ana_rgc3;
mpcs->regmap = regmap;
mpcs->flags = flags;
mpcs->pcs.ops = &mtk_pcs_lynxi_ops;
mpcs->pcs.poll = true;
mpcs->interface = PHY_INTERFACE_MODE_NA;
return &mpcs->pcs;
} }
EXPORT_SYMBOL(mtk_pcs_lynxi_create);
struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id) void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs)
{ {
if (!ss->pcs[id].regmap) if (!pcs)
return NULL; return;
return &ss->pcs[id].pcs; kfree(pcs_to_mtk_pcs_lynxi(pcs));
} }
EXPORT_SYMBOL(mtk_pcs_lynxi_destroy);
MODULE_LICENSE("GPL");
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LINUX_PCS_MTK_LYNXI_H
#define __LINUX_PCS_MTK_LYNXI_H
#include <linux/phylink.h>
#include <linux/regmap.h>
#define MTK_SGMII_FLAG_PN_SWAP BIT(0)
struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
struct regmap *regmap,
u32 ana_rgc3, u32 flags);
void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment