From 64175ffb7911f5fcd3907df09fdb9bfab53ee641 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 7 Apr 2017 17:42:08 +0200 Subject: mediatek: various fixes for v4.9 * adds MT7530 DSA support * backport latest ethernet driver * add PMIC leds * add auxadc support * add efuse support * add thermal sensor support * add irq affinity support for ethernet still todo * DSA multi cpu support Signed-off-by: John Crispin --- ...soc-mediatek-Add-MT2701-power-dt-bindings.patch | 79 + ...soc-mediatek-Add-MT2701-power-dt-bindings.patch | 44 - ...k-Refine-scpsys-to-support-multiple-platf.patch | 491 +++++ ...015-soc-mediatek-Add-MT2701-scpsys-driver.patch | 198 ++ .../patches-4.9/0071-pwm-add-pwm-mediatek.patch | 44 +- .../linux/mediatek/patches-4.9/0083-mfd-led3.patch | 43 + .../mediatek/patches-4.9/0085-pmic-led0.patch | 94 + .../mediatek/patches-4.9/0086-pmic-led1.patch | 40 + .../mediatek/patches-4.9/0087-pmic-led2.patch | 558 +++++ .../mediatek/patches-4.9/0088-pmic-led3.patch | 44 + target/linux/mediatek/patches-4.9/0091-dsa1.patch | 127 ++ .../0091-net-next-mediatek-fix-DQL-support.patch | 95 + target/linux/mediatek/patches-4.9/0092-dsa2.patch | 219 ++ target/linux/mediatek/patches-4.9/0092-dsa3.patch | 67 + target/linux/mediatek/patches-4.9/0092-dsa4.patch | 46 + target/linux/mediatek/patches-4.9/0092-dsa5.patch | 1608 ++++++++++++++ .../mediatek/patches-4.9/0093-dsa-compat.patch | 98 + .../mediatek/patches-4.9/0094-net-affinity.patch | 40 + .../0101-net-mediatek-add-gsw-mt7530-driver.patch | 2322 -------------------- 19 files changed, 3858 insertions(+), 2399 deletions(-) create mode 100644 target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch delete mode 100644 target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch create mode 100644 target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch create mode 100644 target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch create mode 100644 target/linux/mediatek/patches-4.9/0083-mfd-led3.patch create mode 100644 target/linux/mediatek/patches-4.9/0085-pmic-led0.patch create mode 100644 target/linux/mediatek/patches-4.9/0086-pmic-led1.patch create mode 100644 target/linux/mediatek/patches-4.9/0087-pmic-led2.patch create mode 100644 target/linux/mediatek/patches-4.9/0088-pmic-led3.patch create mode 100644 target/linux/mediatek/patches-4.9/0091-dsa1.patch create mode 100644 target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch create mode 100644 target/linux/mediatek/patches-4.9/0092-dsa2.patch create mode 100644 target/linux/mediatek/patches-4.9/0092-dsa3.patch create mode 100644 target/linux/mediatek/patches-4.9/0092-dsa4.patch create mode 100644 target/linux/mediatek/patches-4.9/0092-dsa5.patch create mode 100644 target/linux/mediatek/patches-4.9/0093-dsa-compat.patch create mode 100644 target/linux/mediatek/patches-4.9/0094-net-affinity.patch delete mode 100644 target/linux/mediatek/patches-4.9/0101-net-mediatek-add-gsw-mt7530-driver.patch (limited to 'target/linux/mediatek/patches-4.9') diff --git a/target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch b/target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch new file mode 100644 index 0000000000..28b3d7f17c --- /dev/null +++ b/target/linux/mediatek/patches-4.9/00013-soc-mediatek-Add-MT2701-power-dt-bindings.patch @@ -0,0 +1,79 @@ +From 3e96c653372d8852c45dcd3bd856975157a0fd6a Mon Sep 17 00:00:00 2001 +From: Shunli Wang +Date: Thu, 20 Oct 2016 16:56:37 +0800 +Subject: [PATCH] soc: mediatek: Add MT2701 power dt-bindings + +Add power dt-bindings for MT2701. + +Signed-off-by: Shunli Wang +Signed-off-by: James Liao +Acked-by: Rob Herring +Reviewed-by: Kevin Hilman +Signed-off-by: Matthias Brugger +--- + .../devicetree/bindings/soc/mediatek/scpsys.txt | 13 +++++++---- + include/dt-bindings/power/mt2701-power.h | 27 ++++++++++++++++++++++ + 2 files changed, 35 insertions(+), 5 deletions(-) + create mode 100644 include/dt-bindings/power/mt2701-power.h + +Index: linux-4.9.14/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt +=================================================================== +--- linux-4.9.14.orig/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt ++++ linux-4.9.14/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt +@@ -9,17 +9,20 @@ domain control. + + The driver implements the Generic PM domain bindings described in + power/power_domain.txt. It provides the power domains defined in +-include/dt-bindings/power/mt8173-power.h. ++include/dt-bindings/power/mt8173-power.h and mt2701-power.h. + + Required properties: +-- compatible: Must be "mediatek,mt8173-scpsys" ++- compatible: Should be one of: ++ - "mediatek,mt2701-scpsys" ++ - "mediatek,mt8173-scpsys" + - #power-domain-cells: Must be 1 + - reg: Address range of the SCPSYS unit + - infracfg: must contain a phandle to the infracfg controller + - clock, clock-names: clocks according to the common clock binding. +- The clocks needed "mm", "mfg", "venc" and "venc_lt". +- These are the clocks which hardware needs to be enabled +- before enabling certain power domains. ++ These are clocks which hardware needs to be ++ enabled before enabling certain power domains. ++ Required clocks for MT2701: "mm", "mfg", "ethif" ++ Required clocks for MT8173: "mm", "mfg", "venc", "venc_lt" + + Optional properties: + - vdec-supply: Power supply for the vdec power domain +Index: linux-4.9.14/include/dt-bindings/power/mt2701-power.h +=================================================================== +--- /dev/null ++++ linux-4.9.14/include/dt-bindings/power/mt2701-power.h +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (C) 2015 MediaTek Inc. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef _DT_BINDINGS_POWER_MT2701_POWER_H ++#define _DT_BINDINGS_POWER_MT2701_POWER_H ++ ++#define MT2701_POWER_DOMAIN_CONN 0 ++#define MT2701_POWER_DOMAIN_DISP 1 ++#define MT2701_POWER_DOMAIN_IFR_MSC 2 ++#define MT2701_POWER_DOMAIN_VDEC 3 ++#define MT2701_POWER_DOMAIN_ISP 4 ++#define MT2701_POWER_DOMAIN_BDP 5 ++#define MT2701_POWER_DOMAIN_ETH 6 ++#define MT2701_POWER_DOMAIN_HIF 7 ++ ++#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */ diff --git a/target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch b/target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch deleted file mode 100644 index 132d6c89c8..0000000000 --- a/target/linux/mediatek/patches-4.9/0004-soc-mediatek-Add-MT2701-power-dt-bindings.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 7c5b29de78f1b15c5bde40a6ca4510fc09588457 Mon Sep 17 00:00:00 2001 -From: Shunli Wang -Date: Wed, 30 Dec 2015 14:41:45 +0800 -Subject: [PATCH 004/102] soc: mediatek: Add MT2701 power dt-bindings - -Add power dt-bindings for MT2701. - -Signed-off-by: Shunli Wang -Signed-off-by: James Liao ---- - include/dt-bindings/power/mt2701-power.h | 27 +++++++++++++++++++++++++++ - 1 file changed, 27 insertions(+) - create mode 100644 include/dt-bindings/power/mt2701-power.h - ---- /dev/null -+++ b/include/dt-bindings/power/mt2701-power.h -@@ -0,0 +1,27 @@ -+/* -+ * Copyright (C) 2015 MediaTek Inc. -+ * -+ * This program is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#ifndef _DT_BINDINGS_POWER_MT2701_POWER_H -+#define _DT_BINDINGS_POWER_MT2701_POWER_H -+ -+#define MT2701_POWER_DOMAIN_CONN 0 -+#define MT2701_POWER_DOMAIN_DISP 1 -+#define MT2701_POWER_DOMAIN_MFG 2 -+#define MT2701_POWER_DOMAIN_VDEC 3 -+#define MT2701_POWER_DOMAIN_ISP 4 -+#define MT2701_POWER_DOMAIN_BDP 5 -+#define MT2701_POWER_DOMAIN_ETH 6 -+#define MT2701_POWER_DOMAIN_HIF 7 -+#define MT2701_POWER_DOMAIN_IFR_MSC 8 -+ -+#endif /* _DT_BINDINGS_POWER_MT2701_POWER_H */ diff --git a/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch b/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch new file mode 100644 index 0000000000..4c9e790d46 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0014-soc-mediatek-Refine-scpsys-to-support-multiple-platf.patch @@ -0,0 +1,491 @@ +From 6078c651947a148c1de543b54fe55af43a63043a Mon Sep 17 00:00:00 2001 +From: James Liao +Date: Thu, 20 Oct 2016 16:56:35 +0800 +Subject: [PATCH 1/2] soc: mediatek: Refine scpsys to support multiple platform + +Refine scpsys driver common code to support multiple SoC / platform. + +Signed-off-by: James Liao +Reviewed-by: Kevin Hilman +Signed-off-by: Matthias Brugger +--- + drivers/soc/mediatek/mtk-scpsys.c | 348 +++++++++++++++++++++++--------------- + 1 file changed, 210 insertions(+), 138 deletions(-) + +diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c +index 837effe19907..722aac80e611 100644 +--- a/drivers/soc/mediatek/mtk-scpsys.c ++++ b/drivers/soc/mediatek/mtk-scpsys.c +@@ -11,17 +11,15 @@ + * GNU General Public License for more details. + */ + #include +-#include ++#include + #include +-#include + #include +-#include + #include + #include + #include +-#include +-#include + #include ++#include ++ + #include + + #define SPM_VDE_PWR_CON 0x0210 +@@ -34,6 +32,7 @@ + #define SPM_MFG_2D_PWR_CON 0x02c0 + #define SPM_MFG_ASYNC_PWR_CON 0x02c4 + #define SPM_USB_PWR_CON 0x02cc ++ + #define SPM_PWR_STATUS 0x060c + #define SPM_PWR_STATUS_2ND 0x0610 + +@@ -55,12 +54,21 @@ + #define PWR_STATUS_USB BIT(25) + + enum clk_id { +- MT8173_CLK_NONE, +- MT8173_CLK_MM, +- MT8173_CLK_MFG, +- MT8173_CLK_VENC, +- MT8173_CLK_VENC_LT, +- MT8173_CLK_MAX, ++ CLK_NONE, ++ CLK_MM, ++ CLK_MFG, ++ CLK_VENC, ++ CLK_VENC_LT, ++ CLK_MAX, ++}; ++ ++static const char * const clk_names[] = { ++ NULL, ++ "mm", ++ "mfg", ++ "venc", ++ "venc_lt", ++ NULL, + }; + + #define MAX_CLKS 2 +@@ -76,98 +84,6 @@ struct scp_domain_data { + bool active_wakeup; + }; + +-static const struct scp_domain_data scp_domain_data[] = { +- [MT8173_POWER_DOMAIN_VDEC] = { +- .name = "vdec", +- .sta_mask = PWR_STATUS_VDEC, +- .ctl_offs = SPM_VDE_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(12, 12), +- .clk_id = {MT8173_CLK_MM}, +- }, +- [MT8173_POWER_DOMAIN_VENC] = { +- .name = "venc", +- .sta_mask = PWR_STATUS_VENC, +- .ctl_offs = SPM_VEN_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(15, 12), +- .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC}, +- }, +- [MT8173_POWER_DOMAIN_ISP] = { +- .name = "isp", +- .sta_mask = PWR_STATUS_ISP, +- .ctl_offs = SPM_ISP_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(13, 12), +- .clk_id = {MT8173_CLK_MM}, +- }, +- [MT8173_POWER_DOMAIN_MM] = { +- .name = "mm", +- .sta_mask = PWR_STATUS_DISP, +- .ctl_offs = SPM_DIS_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(12, 12), +- .clk_id = {MT8173_CLK_MM}, +- .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | +- MT8173_TOP_AXI_PROT_EN_MM_M1, +- }, +- [MT8173_POWER_DOMAIN_VENC_LT] = { +- .name = "venc_lt", +- .sta_mask = PWR_STATUS_VENC_LT, +- .ctl_offs = SPM_VEN2_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(15, 12), +- .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT}, +- }, +- [MT8173_POWER_DOMAIN_AUDIO] = { +- .name = "audio", +- .sta_mask = PWR_STATUS_AUDIO, +- .ctl_offs = SPM_AUDIO_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(15, 12), +- .clk_id = {MT8173_CLK_NONE}, +- }, +- [MT8173_POWER_DOMAIN_USB] = { +- .name = "usb", +- .sta_mask = PWR_STATUS_USB, +- .ctl_offs = SPM_USB_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(15, 12), +- .clk_id = {MT8173_CLK_NONE}, +- .active_wakeup = true, +- }, +- [MT8173_POWER_DOMAIN_MFG_ASYNC] = { +- .name = "mfg_async", +- .sta_mask = PWR_STATUS_MFG_ASYNC, +- .ctl_offs = SPM_MFG_ASYNC_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = 0, +- .clk_id = {MT8173_CLK_MFG}, +- }, +- [MT8173_POWER_DOMAIN_MFG_2D] = { +- .name = "mfg_2d", +- .sta_mask = PWR_STATUS_MFG_2D, +- .ctl_offs = SPM_MFG_2D_PWR_CON, +- .sram_pdn_bits = GENMASK(11, 8), +- .sram_pdn_ack_bits = GENMASK(13, 12), +- .clk_id = {MT8173_CLK_NONE}, +- }, +- [MT8173_POWER_DOMAIN_MFG] = { +- .name = "mfg", +- .sta_mask = PWR_STATUS_MFG, +- .ctl_offs = SPM_MFG_PWR_CON, +- .sram_pdn_bits = GENMASK(13, 8), +- .sram_pdn_ack_bits = GENMASK(21, 16), +- .clk_id = {MT8173_CLK_NONE}, +- .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | +- MT8173_TOP_AXI_PROT_EN_MFG_M0 | +- MT8173_TOP_AXI_PROT_EN_MFG_M1 | +- MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, +- }, +-}; +- +-#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data) +- + struct scp; + + struct scp_domain { +@@ -179,7 +95,7 @@ struct scp_domain { + }; + + struct scp { +- struct scp_domain domains[NUM_DOMAINS]; ++ struct scp_domain *domains; + struct genpd_onecell_data pd_data; + struct device *dev; + void __iomem *base; +@@ -408,57 +324,55 @@ static bool scpsys_active_wakeup(struct device *dev) + return scpd->data->active_wakeup; + } + +-static int scpsys_probe(struct platform_device *pdev) ++static void init_clks(struct platform_device *pdev, struct clk **clk) ++{ ++ int i; ++ ++ for (i = CLK_NONE + 1; i < CLK_MAX; i++) ++ clk[i] = devm_clk_get(&pdev->dev, clk_names[i]); ++} ++ ++static struct scp *init_scp(struct platform_device *pdev, ++ const struct scp_domain_data *scp_domain_data, int num) + { + struct genpd_onecell_data *pd_data; + struct resource *res; +- int i, j, ret; ++ int i, j; + struct scp *scp; +- struct clk *clk[MT8173_CLK_MAX]; ++ struct clk *clk[CLK_MAX]; + + scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL); + if (!scp) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + + scp->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + scp->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(scp->base)) +- return PTR_ERR(scp->base); ++ return ERR_CAST(scp->base); ++ ++ scp->domains = devm_kzalloc(&pdev->dev, ++ sizeof(*scp->domains) * num, GFP_KERNEL); ++ if (!scp->domains) ++ return ERR_PTR(-ENOMEM); + + pd_data = &scp->pd_data; + + pd_data->domains = devm_kzalloc(&pdev->dev, +- sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL); ++ sizeof(*pd_data->domains) * num, GFP_KERNEL); + if (!pd_data->domains) +- return -ENOMEM; +- +- clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm"); +- if (IS_ERR(clk[MT8173_CLK_MM])) +- return PTR_ERR(clk[MT8173_CLK_MM]); +- +- clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg"); +- if (IS_ERR(clk[MT8173_CLK_MFG])) +- return PTR_ERR(clk[MT8173_CLK_MFG]); +- +- clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc"); +- if (IS_ERR(clk[MT8173_CLK_VENC])) +- return PTR_ERR(clk[MT8173_CLK_VENC]); +- +- clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt"); +- if (IS_ERR(clk[MT8173_CLK_VENC_LT])) +- return PTR_ERR(clk[MT8173_CLK_VENC_LT]); ++ return ERR_PTR(-ENOMEM); + + scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "infracfg"); + if (IS_ERR(scp->infracfg)) { + dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n", + PTR_ERR(scp->infracfg)); +- return PTR_ERR(scp->infracfg); ++ return ERR_CAST(scp->infracfg); + } + +- for (i = 0; i < NUM_DOMAINS; i++) { ++ for (i = 0; i < num; i++) { + struct scp_domain *scpd = &scp->domains[i]; + const struct scp_domain_data *data = &scp_domain_data[i]; + +@@ -467,13 +381,15 @@ static int scpsys_probe(struct platform_device *pdev) + if (PTR_ERR(scpd->supply) == -ENODEV) + scpd->supply = NULL; + else +- return PTR_ERR(scpd->supply); ++ return ERR_CAST(scpd->supply); + } + } + +- pd_data->num_domains = NUM_DOMAINS; ++ pd_data->num_domains = num; + +- for (i = 0; i < NUM_DOMAINS; i++) { ++ init_clks(pdev, clk); ++ ++ for (i = 0; i < num; i++) { + struct scp_domain *scpd = &scp->domains[i]; + struct generic_pm_domain *genpd = &scpd->genpd; + const struct scp_domain_data *data = &scp_domain_data[i]; +@@ -482,13 +398,37 @@ static int scpsys_probe(struct platform_device *pdev) + scpd->scp = scp; + + scpd->data = data; +- for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) +- scpd->clk[j] = clk[data->clk_id[j]]; ++ ++ for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) { ++ struct clk *c = clk[data->clk_id[j]]; ++ ++ if (IS_ERR(c)) { ++ dev_err(&pdev->dev, "%s: clk unavailable\n", ++ data->name); ++ return ERR_CAST(c); ++ } ++ ++ scpd->clk[j] = c; ++ } + + genpd->name = data->name; + genpd->power_off = scpsys_power_off; + genpd->power_on = scpsys_power_on; + genpd->dev_ops.active_wakeup = scpsys_active_wakeup; ++ } ++ ++ return scp; ++} ++ ++static void mtk_register_power_domains(struct platform_device *pdev, ++ struct scp *scp, int num) ++{ ++ struct genpd_onecell_data *pd_data; ++ int i, ret; ++ ++ for (i = 0; i < num; i++) { ++ struct scp_domain *scpd = &scp->domains[i]; ++ struct generic_pm_domain *genpd = &scpd->genpd; + + /* + * Initially turn on all domains to make the domains usable +@@ -507,6 +447,123 @@ static int scpsys_probe(struct platform_device *pdev) + * valid. + */ + ++ pd_data = &scp->pd_data; ++ ++ ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); ++ if (ret) ++ dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); ++} ++ ++/* ++ * MT8173 power domain support ++ */ ++ ++static const struct scp_domain_data scp_domain_data_mt8173[] = { ++ [MT8173_POWER_DOMAIN_VDEC] = { ++ .name = "vdec", ++ .sta_mask = PWR_STATUS_VDEC, ++ .ctl_offs = SPM_VDE_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(12, 12), ++ .clk_id = {CLK_MM}, ++ }, ++ [MT8173_POWER_DOMAIN_VENC] = { ++ .name = "venc", ++ .sta_mask = PWR_STATUS_VENC, ++ .ctl_offs = SPM_VEN_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_MM, CLK_VENC}, ++ }, ++ [MT8173_POWER_DOMAIN_ISP] = { ++ .name = "isp", ++ .sta_mask = PWR_STATUS_ISP, ++ .ctl_offs = SPM_ISP_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(13, 12), ++ .clk_id = {CLK_MM}, ++ }, ++ [MT8173_POWER_DOMAIN_MM] = { ++ .name = "mm", ++ .sta_mask = PWR_STATUS_DISP, ++ .ctl_offs = SPM_DIS_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(12, 12), ++ .clk_id = {CLK_MM}, ++ .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | ++ MT8173_TOP_AXI_PROT_EN_MM_M1, ++ }, ++ [MT8173_POWER_DOMAIN_VENC_LT] = { ++ .name = "venc_lt", ++ .sta_mask = PWR_STATUS_VENC_LT, ++ .ctl_offs = SPM_VEN2_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_MM, CLK_VENC_LT}, ++ }, ++ [MT8173_POWER_DOMAIN_AUDIO] = { ++ .name = "audio", ++ .sta_mask = PWR_STATUS_AUDIO, ++ .ctl_offs = SPM_AUDIO_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_NONE}, ++ }, ++ [MT8173_POWER_DOMAIN_USB] = { ++ .name = "usb", ++ .sta_mask = PWR_STATUS_USB, ++ .ctl_offs = SPM_USB_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_NONE}, ++ .active_wakeup = true, ++ }, ++ [MT8173_POWER_DOMAIN_MFG_ASYNC] = { ++ .name = "mfg_async", ++ .sta_mask = PWR_STATUS_MFG_ASYNC, ++ .ctl_offs = SPM_MFG_ASYNC_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = 0, ++ .clk_id = {CLK_MFG}, ++ }, ++ [MT8173_POWER_DOMAIN_MFG_2D] = { ++ .name = "mfg_2d", ++ .sta_mask = PWR_STATUS_MFG_2D, ++ .ctl_offs = SPM_MFG_2D_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(13, 12), ++ .clk_id = {CLK_NONE}, ++ }, ++ [MT8173_POWER_DOMAIN_MFG] = { ++ .name = "mfg", ++ .sta_mask = PWR_STATUS_MFG, ++ .ctl_offs = SPM_MFG_PWR_CON, ++ .sram_pdn_bits = GENMASK(13, 8), ++ .sram_pdn_ack_bits = GENMASK(21, 16), ++ .clk_id = {CLK_NONE}, ++ .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | ++ MT8173_TOP_AXI_PROT_EN_MFG_M0 | ++ MT8173_TOP_AXI_PROT_EN_MFG_M1 | ++ MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, ++ }, ++}; ++ ++#define NUM_DOMAINS_MT8173 ARRAY_SIZE(scp_domain_data_mt8173) ++ ++static int __init scpsys_probe_mt8173(struct platform_device *pdev) ++{ ++ struct scp *scp; ++ struct genpd_onecell_data *pd_data; ++ int ret; ++ ++ scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173); ++ if (IS_ERR(scp)) ++ return PTR_ERR(scp); ++ ++ mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173); ++ ++ pd_data = &scp->pd_data; ++ + ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC], + pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]); + if (ret && IS_ENABLED(CONFIG_PM)) +@@ -517,21 +574,36 @@ static int scpsys_probe(struct platform_device *pdev) + if (ret && IS_ENABLED(CONFIG_PM)) + dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret); + +- ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); +- if (ret) +- dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); +- + return 0; + } + ++/* ++ * scpsys driver init ++ */ ++ + static const struct of_device_id of_scpsys_match_tbl[] = { + { + .compatible = "mediatek,mt8173-scpsys", ++ .data = scpsys_probe_mt8173, + }, { + /* sentinel */ + } + }; + ++static int scpsys_probe(struct platform_device *pdev) ++{ ++ int (*probe)(struct platform_device *); ++ const struct of_device_id *of_id; ++ ++ of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node); ++ if (!of_id || !of_id->data) ++ return -EINVAL; ++ ++ probe = of_id->data; ++ ++ return probe(pdev); ++} ++ + static struct platform_driver scpsys_drv = { + .probe = scpsys_probe, + .driver = { +-- +2.11.0 + diff --git a/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch b/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch new file mode 100644 index 0000000000..c56a8a974f --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0015-soc-mediatek-Add-MT2701-scpsys-driver.patch @@ -0,0 +1,198 @@ +From 112ef1882e12094c823937f9d72f2f598db02df7 Mon Sep 17 00:00:00 2001 +From: Shunli Wang +Date: Thu, 20 Oct 2016 16:56:38 +0800 +Subject: [PATCH 2/2] soc: mediatek: Add MT2701 scpsys driver + +Add scpsys driver for MT2701. + +mtk-scpsys now supports MT8173 (arm64) and MT2701 (arm). So it should +be enabled on both arm64 and arm platforms. + +Signed-off-by: Shunli Wang +Signed-off-by: James Liao +Reviewed-by: Kevin Hilman +Signed-off-by: Matthias Brugger +--- + drivers/soc/mediatek/Kconfig | 2 +- + drivers/soc/mediatek/mtk-scpsys.c | 117 +++++++++++++++++++++++++++++++++++++- + 2 files changed, 117 insertions(+), 2 deletions(-) + +Index: linux-4.9.14/drivers/soc/mediatek/Kconfig +=================================================================== +--- linux-4.9.14.orig/drivers/soc/mediatek/Kconfig ++++ linux-4.9.14/drivers/soc/mediatek/Kconfig +@@ -23,7 +23,7 @@ config MTK_PMIC_WRAP + config MTK_SCPSYS + bool "MediaTek SCPSYS Support" + depends on ARCH_MEDIATEK || COMPILE_TEST +- default ARM64 && ARCH_MEDIATEK ++ default ARCH_MEDIATEK + select REGMAP + select MTK_INFRACFG + select PM_GENERIC_DOMAINS if PM +Index: linux-4.9.14/drivers/soc/mediatek/mtk-scpsys.c +=================================================================== +--- linux-4.9.14.orig/drivers/soc/mediatek/mtk-scpsys.c ++++ linux-4.9.14/drivers/soc/mediatek/mtk-scpsys.c +@@ -20,6 +20,7 @@ + #include + #include + ++#include + #include + + #define SPM_VDE_PWR_CON 0x0210 +@@ -27,8 +28,13 @@ + #define SPM_VEN_PWR_CON 0x0230 + #define SPM_ISP_PWR_CON 0x0238 + #define SPM_DIS_PWR_CON 0x023c ++#define SPM_CONN_PWR_CON 0x0280 + #define SPM_VEN2_PWR_CON 0x0298 +-#define SPM_AUDIO_PWR_CON 0x029c ++#define SPM_AUDIO_PWR_CON 0x029c /* MT8173 */ ++#define SPM_BDP_PWR_CON 0x029c /* MT2701 */ ++#define SPM_ETH_PWR_CON 0x02a0 ++#define SPM_HIF_PWR_CON 0x02a4 ++#define SPM_IFR_MSC_PWR_CON 0x02a8 + #define SPM_MFG_2D_PWR_CON 0x02c0 + #define SPM_MFG_ASYNC_PWR_CON 0x02c4 + #define SPM_USB_PWR_CON 0x02cc +@@ -42,10 +48,15 @@ + #define PWR_ON_2ND_BIT BIT(3) + #define PWR_CLK_DIS_BIT BIT(4) + ++#define PWR_STATUS_CONN BIT(1) + #define PWR_STATUS_DISP BIT(3) + #define PWR_STATUS_MFG BIT(4) + #define PWR_STATUS_ISP BIT(5) + #define PWR_STATUS_VDEC BIT(7) ++#define PWR_STATUS_BDP BIT(14) ++#define PWR_STATUS_ETH BIT(15) ++#define PWR_STATUS_HIF BIT(16) ++#define PWR_STATUS_IFR_MSC BIT(17) + #define PWR_STATUS_VENC_LT BIT(20) + #define PWR_STATUS_VENC BIT(21) + #define PWR_STATUS_MFG_2D BIT(22) +@@ -59,6 +70,7 @@ enum clk_id { + CLK_MFG, + CLK_VENC, + CLK_VENC_LT, ++ CLK_ETHIF, + CLK_MAX, + }; + +@@ -68,6 +80,7 @@ static const char * const clk_names[] = + "mfg", + "venc", + "venc_lt", ++ "ethif", + NULL, + }; + +@@ -455,6 +468,96 @@ static void mtk_register_power_domains(s + } + + /* ++ * MT2701 power domain support ++ */ ++ ++static const struct scp_domain_data scp_domain_data_mt2701[] = { ++ [MT2701_POWER_DOMAIN_CONN] = { ++ .name = "conn", ++ .sta_mask = PWR_STATUS_CONN, ++ .ctl_offs = SPM_CONN_PWR_CON, ++ .bus_prot_mask = 0x0104, ++ .clk_id = {CLK_NONE}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_DISP] = { ++ .name = "disp", ++ .sta_mask = PWR_STATUS_DISP, ++ .ctl_offs = SPM_DIS_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .clk_id = {CLK_MM}, ++ .bus_prot_mask = 0x0002, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_VDEC] = { ++ .name = "vdec", ++ .sta_mask = PWR_STATUS_VDEC, ++ .ctl_offs = SPM_VDE_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(12, 12), ++ .clk_id = {CLK_MM}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_ISP] = { ++ .name = "isp", ++ .sta_mask = PWR_STATUS_ISP, ++ .ctl_offs = SPM_ISP_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(13, 12), ++ .clk_id = {CLK_MM}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_BDP] = { ++ .name = "bdp", ++ .sta_mask = PWR_STATUS_BDP, ++ .ctl_offs = SPM_BDP_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .clk_id = {CLK_NONE}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_ETH] = { ++ .name = "eth", ++ .sta_mask = PWR_STATUS_ETH, ++ .ctl_offs = SPM_ETH_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_ETHIF}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_HIF] = { ++ .name = "hif", ++ .sta_mask = PWR_STATUS_HIF, ++ .ctl_offs = SPM_HIF_PWR_CON, ++ .sram_pdn_bits = GENMASK(11, 8), ++ .sram_pdn_ack_bits = GENMASK(15, 12), ++ .clk_id = {CLK_ETHIF}, ++ .active_wakeup = true, ++ }, ++ [MT2701_POWER_DOMAIN_IFR_MSC] = { ++ .name = "ifr_msc", ++ .sta_mask = PWR_STATUS_IFR_MSC, ++ .ctl_offs = SPM_IFR_MSC_PWR_CON, ++ .clk_id = {CLK_NONE}, ++ .active_wakeup = true, ++ }, ++}; ++ ++#define NUM_DOMAINS_MT2701 ARRAY_SIZE(scp_domain_data_mt2701) ++ ++static int __init scpsys_probe_mt2701(struct platform_device *pdev) ++{ ++ struct scp *scp; ++ ++ scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701); ++ if (IS_ERR(scp)) ++ return PTR_ERR(scp); ++ ++ mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701); ++ ++ return 0; ++} ++ ++/* + * MT8173 power domain support + */ + +@@ -583,6 +686,9 @@ static int __init scpsys_probe_mt8173(st + + static const struct of_device_id of_scpsys_match_tbl[] = { + { ++ .compatible = "mediatek,mt2701-scpsys", ++ .data = scpsys_probe_mt2701, ++ }, { + .compatible = "mediatek,mt8173-scpsys", + .data = scpsys_probe_mt8173, + }, { diff --git a/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch b/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch index 24437cfb48..cf604f4cd0 100644 --- a/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch +++ b/target/linux/mediatek/patches-4.9/0071-pwm-add-pwm-mediatek.patch @@ -13,36 +13,10 @@ Signed-off-by: John Crispin 5 files changed, 279 insertions(+) create mode 100644 drivers/pwm/pwm-mediatek.c ---- a/arch/arm/boot/dts/mt7623-evb.dts -+++ b/arch/arm/boot/dts/mt7623-evb.dts -@@ -26,8 +26,25 @@ - memory { - reg = <0 0x80000000 0 0x40000000>; - }; -+/* -+ pwm_pins: pwm { -+ pins_pwm1 { -+ pinmux = ; -+ }; -+ -+ pins_pwm2 { -+ pinmux = ; -+ }; -+ };*/ -+ - }; - - &uart2 { - status = "okay"; - }; -+ -+/*&pwm { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&pwm_pins>; -+ status = "okay"; -+};*/ ---- a/drivers/pwm/Kconfig -+++ b/drivers/pwm/Kconfig +Index: linux-4.9.17/drivers/pwm/Kconfig +=================================================================== +--- linux-4.9.17.orig/drivers/pwm/Kconfig ++++ linux-4.9.17/drivers/pwm/Kconfig @@ -282,6 +282,15 @@ config PWM_MTK_DISP To compile this driver as a module, choose M here: the module will be called pwm-mtk-disp. @@ -59,8 +33,10 @@ Signed-off-by: John Crispin config PWM_MXS tristate "Freescale MXS PWM support" depends on ARCH_MXS && OF ---- a/drivers/pwm/Makefile -+++ b/drivers/pwm/Makefile +Index: linux-4.9.17/drivers/pwm/Makefile +=================================================================== +--- linux-4.9.17.orig/drivers/pwm/Makefile ++++ linux-4.9.17/drivers/pwm/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o @@ -69,8 +45,10 @@ Signed-off-by: John Crispin obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o +Index: linux-4.9.17/drivers/pwm/pwm-mediatek.c +=================================================================== --- /dev/null -+++ b/drivers/pwm/pwm-mediatek.c ++++ linux-4.9.17/drivers/pwm/pwm-mediatek.c @@ -0,0 +1,230 @@ +/* + * Mediatek Pulse Width Modulator driver diff --git a/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch b/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch new file mode 100644 index 0000000000..a72da69e00 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0083-mfd-led3.patch @@ -0,0 +1,43 @@ +From patchwork Fri Feb 24 18:47:21 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v4,4/4] mfd: mt6397: Add MT6323 LED support into MT6397 driver +From: sean.wang@mediatek.com +X-Patchwork-Id: 9591021 +Message-Id: <1487962041-6548-5-git-send-email-sean.wang@mediatek.com> +To: , , , + , , , + +Cc: devicetree@vger.kernel.org, keyhaede@gmail.com, + Sean Wang , linux-kernel@vger.kernel.org, + linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org, + linux-arm-kernel@lists.infradead.org +Date: Sat, 25 Feb 2017 02:47:21 +0800 + +From: Sean Wang + +Add compatible string as "mt6323-led" that will make +the OF core spawn child devices for the LED subnode +of that MT6323 MFD device. + +Signed-off-by: Sean Wang +--- + drivers/mfd/mt6397-core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c +index e14d8b0..8e601c8 100644 +--- a/drivers/mfd/mt6397-core.c ++++ b/drivers/mfd/mt6397-core.c +@@ -48,6 +48,10 @@ + .name = "mt6323-regulator", + .of_compatible = "mediatek,mt6323-regulator" + }, ++ { ++ .name = "mt6323-led", ++ .of_compatible = "mediatek,mt6323-led" ++ }, + }; + + static const struct mfd_cell mt6397_devs[] = { diff --git a/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch b/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch new file mode 100644 index 0000000000..96662dd894 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0085-pmic-led0.patch @@ -0,0 +1,94 @@ +From patchwork Mon Mar 20 06:47:24 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v6,1/4] dt-bindings: leds: Add document bindings for leds-mt6323 +From: sean.wang@mediatek.com +X-Patchwork-Id: 9633073 +Message-Id: <1489992447-13007-2-git-send-email-sean.wang@mediatek.com> +To: , , , + , , , + +Cc: devicetree@vger.kernel.org, keyhaede@gmail.com, + Sean Wang , linux-kernel@vger.kernel.org, + linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org, + linux-arm-kernel@lists.infradead.org +Date: Mon, 20 Mar 2017 14:47:24 +0800 + +From: Sean Wang + +This patch adds documentation for devicetree bindings for LED support on +MT6323 PMIC. + +Signed-off-by: Sean Wang +--- + .../devicetree/bindings/leds/leds-mt6323.txt | 60 ++++++++++++++++++++++ + 1 file changed, 60 insertions(+) + create mode 100644 Documentation/devicetree/bindings/leds/leds-mt6323.txt + +diff --git a/Documentation/devicetree/bindings/leds/leds-mt6323.txt b/Documentation/devicetree/bindings/leds/leds-mt6323.txt +new file mode 100644 +index 0000000..ac38472 +--- /dev/null ++++ b/Documentation/devicetree/bindings/leds/leds-mt6323.txt +@@ -0,0 +1,60 @@ ++Device Tree Bindings for LED support on MT6323 PMIC ++ ++MT6323 LED controller is subfunction provided by MT6323 PMIC, so the LED ++controllers are defined as the subnode of the function node provided by MT6323 ++PMIC controller that is being defined as one kind of Muti-Function Device (MFD) ++using shared bus called PMIC wrapper for each subfunction to access remote ++MT6323 PMIC hardware. ++ ++For MT6323 MFD bindings see: ++Documentation/devicetree/bindings/mfd/mt6397.txt ++For MediaTek PMIC wrapper bindings see: ++Documentation/devicetree/bindings/soc/mediatek/pwrap.txt ++ ++Required properties: ++- compatible : Must be "mediatek,mt6323-led" ++- address-cells : Must be 1 ++- size-cells : Must be 0 ++ ++Each led is represented as a child node of the mediatek,mt6323-led that ++describes the initial behavior for each LED physically and currently only four ++LED child nodes can be supported. ++ ++Required properties for the LED child node: ++- reg : LED channel number (0..3) ++ ++Optional properties for the LED child node: ++- label : See Documentation/devicetree/bindings/leds/common.txt ++- linux,default-trigger : See Documentation/devicetree/bindings/leds/common.txt ++- default-state: See Documentation/devicetree/bindings/leds/common.txt ++ ++Example: ++ ++ mt6323: pmic { ++ compatible = "mediatek,mt6323"; ++ ++ ... ++ ++ mt6323led: leds { ++ compatible = "mediatek,mt6323-led"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0>; ++ label = "LED0"; ++ linux,default-trigger = "timer"; ++ default-state = "on"; ++ }; ++ led@1 { ++ reg = <1>; ++ label = "LED1"; ++ default-state = "off"; ++ }; ++ led@2 { ++ reg = <2>; ++ label = "LED2"; ++ default-state = "on"; ++ }; ++ }; ++ }; diff --git a/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch b/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch new file mode 100644 index 0000000000..215b1b0d02 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0086-pmic-led1.patch @@ -0,0 +1,40 @@ +From patchwork Mon Mar 20 06:47:25 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v6, + 2/4] dt-bindings: mfd: Add the description for LED as the sub module +From: sean.wang@mediatek.com +X-Patchwork-Id: 9633089 +Message-Id: <1489992447-13007-3-git-send-email-sean.wang@mediatek.com> +To: , , , + , , , + +Cc: devicetree@vger.kernel.org, keyhaede@gmail.com, + Sean Wang , linux-kernel@vger.kernel.org, + linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org, + linux-arm-kernel@lists.infradead.org +Date: Mon, 20 Mar 2017 14:47:25 +0800 + +From: Sean Wang + +This patch adds description for LED as the sub-module on MT6397/MT6323 +multifunction device. + +Signed-off-by: Sean Wang +--- + Documentation/devicetree/bindings/mfd/mt6397.txt | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/mfd/mt6397.txt b/Documentation/devicetree/bindings/mfd/mt6397.txt +index c568d52..522a3bb 100644 +--- a/Documentation/devicetree/bindings/mfd/mt6397.txt ++++ b/Documentation/devicetree/bindings/mfd/mt6397.txt +@@ -6,6 +6,7 @@ MT6397/MT6323 is a multifunction device with the following sub modules: + - Audio codec + - GPIO + - Clock ++- LED + + It is interfaced to host controller using SPI interface by a proprietary hardware + called PMIC wrapper or pwrap. MT6397/MT6323 MFD is a child device of pwrap. diff --git a/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch b/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch new file mode 100644 index 0000000000..f3bc921e3d --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0087-pmic-led2.patch @@ -0,0 +1,558 @@ +From patchwork Mon Mar 20 06:47:26 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v6,3/4] leds: Add LED support for MT6323 PMIC +From: sean.wang@mediatek.com +X-Patchwork-Id: 9633081 +Message-Id: <1489992447-13007-4-git-send-email-sean.wang@mediatek.com> +To: , , , + , , , + +Cc: devicetree@vger.kernel.org, keyhaede@gmail.com, + Sean Wang , linux-kernel@vger.kernel.org, + linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org, + linux-arm-kernel@lists.infradead.org +Date: Mon, 20 Mar 2017 14:47:26 +0800 + +From: Sean Wang + +MT6323 PMIC is a multi-function device that includes LED function. +It allows attaching up to 4 LEDs which can either be on, off or dimmed +and/or blinked with the controller. + +Signed-off-by: Sean Wang +Reviewed-by: Jacek Anaszewski +--- + drivers/leds/Kconfig | 8 + + drivers/leds/Makefile | 1 + + drivers/leds/leds-mt6323.c | 502 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 511 insertions(+) + create mode 100644 drivers/leds/leds-mt6323.c + +Index: linux-4.9.17/drivers/leds/Kconfig +=================================================================== +--- linux-4.9.17.orig/drivers/leds/Kconfig ++++ linux-4.9.17/drivers/leds/Kconfig +@@ -117,6 +117,14 @@ config LEDS_MIKROTIK_RB532 + This option enables support for the so called "User LED" of + Mikrotik's Routerboard 532. + ++config LEDS_MT6323 ++ tristate "LED Support for Mediatek MT6323 PMIC" ++ depends on LEDS_CLASS ++ depends on MFD_MT6397 ++ help ++ This option enables support for on-chip LED drivers found on ++ Mediatek MT6323 PMIC. ++ + config LEDS_S3C24XX + tristate "LED Support for Samsung S3C24XX GPIO LEDs" + depends on LEDS_CLASS +Index: linux-4.9.17/drivers/leds/leds-mt6323.c +=================================================================== +--- /dev/null ++++ linux-4.9.17/drivers/leds/leds-mt6323.c +@@ -0,0 +1,502 @@ ++/* ++ * LED driver for Mediatek MT6323 PMIC ++ * ++ * Copyright (C) 2017 Sean Wang ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Register field for MT6323_TOP_CKPDN0 to enable ++ * 32K clock common for LED device. ++ */ ++#define MT6323_RG_DRV_32K_CK_PDN BIT(11) ++#define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11) ++ ++/* ++ * Register field for MT6323_TOP_CKPDN2 to enable ++ * individual clock for LED device. ++ */ ++#define MT6323_RG_ISINK_CK_PDN(i) BIT(i) ++#define MT6323_RG_ISINK_CK_PDN_MASK(i) BIT(i) ++ ++/* ++ * Register field for MT6323_TOP_CKCON1 to select ++ * clock source. ++ */ ++#define MT6323_RG_ISINK_CK_SEL_MASK(i) (BIT(10) << (i)) ++ ++/* ++ * Register for MT6323_ISINK_CON0 to setup the ++ * duty cycle of the blink. ++ */ ++#define MT6323_ISINK_CON0(i) (MT6323_ISINK0_CON0 + 0x8 * (i)) ++#define MT6323_ISINK_DIM_DUTY_MASK (0x1f << 8) ++#define MT6323_ISINK_DIM_DUTY(i) (((i) << 8) & \ ++ MT6323_ISINK_DIM_DUTY_MASK) ++ ++/* Register to setup the period of the blink. */ ++#define MT6323_ISINK_CON1(i) (MT6323_ISINK0_CON1 + 0x8 * (i)) ++#define MT6323_ISINK_DIM_FSEL_MASK (0xffff) ++#define MT6323_ISINK_DIM_FSEL(i) ((i) & MT6323_ISINK_DIM_FSEL_MASK) ++ ++/* Register to control the brightness. */ ++#define MT6323_ISINK_CON2(i) (MT6323_ISINK0_CON2 + 0x8 * (i)) ++#define MT6323_ISINK_CH_STEP_SHIFT 12 ++#define MT6323_ISINK_CH_STEP_MASK (0x7 << 12) ++#define MT6323_ISINK_CH_STEP(i) (((i) << 12) & \ ++ MT6323_ISINK_CH_STEP_MASK) ++#define MT6323_ISINK_SFSTR0_TC_MASK (0x3 << 1) ++#define MT6323_ISINK_SFSTR0_TC(i) (((i) << 1) & \ ++ MT6323_ISINK_SFSTR0_TC_MASK) ++#define MT6323_ISINK_SFSTR0_EN_MASK BIT(0) ++#define MT6323_ISINK_SFSTR0_EN BIT(0) ++ ++/* Register to LED channel enablement. */ ++#define MT6323_ISINK_CH_EN_MASK(i) BIT(i) ++#define MT6323_ISINK_CH_EN(i) BIT(i) ++ ++#define MT6323_MAX_PERIOD 10000 ++#define MT6323_MAX_LEDS 4 ++#define MT6323_MAX_BRIGHTNESS 6 ++#define MT6323_UNIT_DUTY 3125 ++#define MT6323_CAL_HW_DUTY(o, p) DIV_ROUND_CLOSEST((o) * 100000ul,\ ++ (p) * MT6323_UNIT_DUTY) ++ ++struct mt6323_leds; ++ ++/** ++ * struct mt6323_led - state container for the LED device ++ * @id: the identifier in MT6323 LED device ++ * @parent: the pointer to MT6323 LED controller ++ * @cdev: LED class device for this LED device ++ * @current_brightness: current state of the LED device ++ */ ++struct mt6323_led { ++ int id; ++ struct mt6323_leds *parent; ++ struct led_classdev cdev; ++ enum led_brightness current_brightness; ++}; ++ ++/** ++ * struct mt6323_leds - state container for holding LED controller ++ * of the driver ++ * @dev: the device pointer ++ * @hw: the underlying hardware providing shared ++ * bus for the register operations ++ * @lock: the lock among process context ++ * @led: the array that contains the state of individual ++ * LED device ++ */ ++struct mt6323_leds { ++ struct device *dev; ++ struct mt6397_chip *hw; ++ /* protect among process context */ ++ struct mutex lock; ++ struct mt6323_led *led[MT6323_MAX_LEDS]; ++}; ++ ++static int mt6323_led_hw_brightness(struct led_classdev *cdev, ++ enum led_brightness brightness) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ struct regmap *regmap = leds->hw->regmap; ++ u32 con2_mask = 0, con2_val = 0; ++ int ret; ++ ++ /* ++ * Setup current output for the corresponding ++ * brightness level. ++ */ ++ con2_mask |= MT6323_ISINK_CH_STEP_MASK | ++ MT6323_ISINK_SFSTR0_TC_MASK | ++ MT6323_ISINK_SFSTR0_EN_MASK; ++ con2_val |= MT6323_ISINK_CH_STEP(brightness - 1) | ++ MT6323_ISINK_SFSTR0_TC(2) | ++ MT6323_ISINK_SFSTR0_EN; ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id), ++ con2_mask, con2_val); ++ return ret; ++} ++ ++static int mt6323_led_hw_off(struct led_classdev *cdev) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ struct regmap *regmap = leds->hw->regmap; ++ unsigned int status; ++ int ret; ++ ++ status = MT6323_ISINK_CH_EN(led->id); ++ ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL, ++ MT6323_ISINK_CH_EN_MASK(led->id), ~status); ++ if (ret < 0) ++ return ret; ++ ++ usleep_range(100, 300); ++ ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2, ++ MT6323_RG_ISINK_CK_PDN_MASK(led->id), ++ MT6323_RG_ISINK_CK_PDN(led->id)); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static enum led_brightness ++mt6323_get_led_hw_brightness(struct led_classdev *cdev) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ struct regmap *regmap = leds->hw->regmap; ++ unsigned int status; ++ int ret; ++ ++ ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status); ++ if (ret < 0) ++ return ret; ++ ++ if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id)) ++ return 0; ++ ++ ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status); ++ if (ret < 0) ++ return ret; ++ ++ if (!(status & MT6323_ISINK_CH_EN(led->id))) ++ return 0; ++ ++ ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status); ++ if (ret < 0) ++ return ret; ++ ++ return ((status & MT6323_ISINK_CH_STEP_MASK) ++ >> MT6323_ISINK_CH_STEP_SHIFT) + 1; ++} ++ ++static int mt6323_led_hw_on(struct led_classdev *cdev, ++ enum led_brightness brightness) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ struct regmap *regmap = leds->hw->regmap; ++ unsigned int status; ++ int ret; ++ ++ /* ++ * Setup required clock source, enable the corresponding ++ * clock and channel and let work with continuous blink as ++ * the default. ++ */ ++ ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1, ++ MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0); ++ if (ret < 0) ++ return ret; ++ ++ status = MT6323_RG_ISINK_CK_PDN(led->id); ++ ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2, ++ MT6323_RG_ISINK_CK_PDN_MASK(led->id), ++ ~status); ++ if (ret < 0) ++ return ret; ++ ++ usleep_range(100, 300); ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL, ++ MT6323_ISINK_CH_EN_MASK(led->id), ++ MT6323_ISINK_CH_EN(led->id)); ++ if (ret < 0) ++ return ret; ++ ++ ret = mt6323_led_hw_brightness(cdev, brightness); ++ if (ret < 0) ++ return ret; ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id), ++ MT6323_ISINK_DIM_DUTY_MASK, ++ MT6323_ISINK_DIM_DUTY(31)); ++ if (ret < 0) ++ return ret; ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id), ++ MT6323_ISINK_DIM_FSEL_MASK, ++ MT6323_ISINK_DIM_FSEL(1000)); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int mt6323_led_set_blink(struct led_classdev *cdev, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ struct regmap *regmap = leds->hw->regmap; ++ unsigned long period; ++ u8 duty_hw; ++ int ret; ++ ++ /* ++ * Units are in ms, if over the hardware able ++ * to support, fallback into software blink ++ */ ++ period = *delay_on + *delay_off; ++ ++ if (period > MT6323_MAX_PERIOD) ++ return -EINVAL; ++ ++ /* ++ * LED subsystem requires a default user ++ * friendly blink pattern for the LED so using ++ * 1Hz duty cycle 50% here if without specific ++ * value delay_on and delay off being assigned. ++ */ ++ if (!*delay_on && !*delay_off) { ++ *delay_on = 500; ++ *delay_off = 500; ++ } ++ ++ /* ++ * Calculate duty_hw based on the percentage of period during ++ * which the led is ON. ++ */ ++ duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period); ++ ++ /* hardware doesn't support zero duty cycle. */ ++ if (!duty_hw) ++ return -EINVAL; ++ ++ mutex_lock(&leds->lock); ++ /* ++ * Set max_brightness as the software blink behavior ++ * when no blink brightness. ++ */ ++ if (!led->current_brightness) { ++ ret = mt6323_led_hw_on(cdev, cdev->max_brightness); ++ if (ret < 0) ++ goto out; ++ led->current_brightness = cdev->max_brightness; ++ } ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id), ++ MT6323_ISINK_DIM_DUTY_MASK, ++ MT6323_ISINK_DIM_DUTY(duty_hw - 1)); ++ if (ret < 0) ++ goto out; ++ ++ ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id), ++ MT6323_ISINK_DIM_FSEL_MASK, ++ MT6323_ISINK_DIM_FSEL(period - 1)); ++out: ++ mutex_unlock(&leds->lock); ++ ++ return ret; ++} ++ ++static int mt6323_led_set_brightness(struct led_classdev *cdev, ++ enum led_brightness brightness) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ struct mt6323_leds *leds = led->parent; ++ int ret; ++ ++ mutex_lock(&leds->lock); ++ ++ if (!led->current_brightness && brightness) { ++ ret = mt6323_led_hw_on(cdev, brightness); ++ if (ret < 0) ++ goto out; ++ } else if (brightness) { ++ ret = mt6323_led_hw_brightness(cdev, brightness); ++ if (ret < 0) ++ goto out; ++ } else { ++ ret = mt6323_led_hw_off(cdev); ++ if (ret < 0) ++ goto out; ++ } ++ ++ led->current_brightness = brightness; ++out: ++ mutex_unlock(&leds->lock); ++ ++ return ret; ++} ++ ++static int mt6323_led_set_dt_default(struct led_classdev *cdev, ++ struct device_node *np) ++{ ++ struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev); ++ const char *state; ++ int ret = 0; ++ ++ led->cdev.name = of_get_property(np, "label", NULL) ? : np->name; ++ led->cdev.default_trigger = of_get_property(np, ++ "linux,default-trigger", ++ NULL); ++ ++ state = of_get_property(np, "default-state", NULL); ++ if (state) { ++ if (!strcmp(state, "keep")) { ++ ret = mt6323_get_led_hw_brightness(cdev); ++ if (ret < 0) ++ return ret; ++ led->current_brightness = ret; ++ ret = 0; ++ } else if (!strcmp(state, "on")) { ++ ret = ++ mt6323_led_set_brightness(cdev, cdev->max_brightness); ++ } else { ++ ret = mt6323_led_set_brightness(cdev, LED_OFF); ++ } ++ } ++ ++ return ret; ++} ++ ++static int mt6323_led_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = pdev->dev.of_node; ++ struct device_node *child; ++ struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent); ++ struct mt6323_leds *leds; ++ struct mt6323_led *led; ++ int ret; ++ unsigned int status; ++ u32 reg; ++ ++ leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL); ++ if (!leds) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, leds); ++ leds->dev = dev; ++ ++ /* ++ * leds->hw points to the underlying bus for the register ++ * controlled. ++ */ ++ leds->hw = hw; ++ mutex_init(&leds->lock); ++ ++ status = MT6323_RG_DRV_32K_CK_PDN; ++ ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0, ++ MT6323_RG_DRV_32K_CK_PDN_MASK, ~status); ++ if (ret < 0) { ++ dev_err(leds->dev, ++ "Failed to update MT6323_TOP_CKPDN0 Register\n"); ++ return ret; ++ } ++ ++ for_each_available_child_of_node(np, child) { ++ ret = of_property_read_u32(child, "reg", ®); ++ if (ret) { ++ dev_err(dev, "Failed to read led 'reg' property\n"); ++ goto put_child_node; ++ } ++ ++ if (reg < 0 || reg > MT6323_MAX_LEDS || leds->led[reg]) { ++ dev_err(dev, "Invalid led reg %u\n", reg); ++ ret = -EINVAL; ++ goto put_child_node; ++ } ++ ++ led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); ++ if (!led) { ++ ret = -ENOMEM; ++ goto put_child_node; ++ } ++ ++ leds->led[reg] = led; ++ leds->led[reg]->id = reg; ++ leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS; ++ leds->led[reg]->cdev.brightness_set_blocking = ++ mt6323_led_set_brightness; ++ leds->led[reg]->cdev.blink_set = mt6323_led_set_blink; ++ leds->led[reg]->cdev.brightness_get = ++ mt6323_get_led_hw_brightness; ++ leds->led[reg]->parent = leds; ++ ++ ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child); ++ if (ret < 0) { ++ dev_err(leds->dev, ++ "Failed to LED set default from devicetree\n"); ++ goto put_child_node; ++ } ++ ++ ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register LED: %d\n", ++ ret); ++ goto put_child_node; ++ } ++ leds->led[reg]->cdev.dev->of_node = child; ++ } ++ ++ return 0; ++ ++put_child_node: ++ of_node_put(child); ++ return ret; ++} ++ ++static int mt6323_led_remove(struct platform_device *pdev) ++{ ++ struct mt6323_leds *leds = platform_get_drvdata(pdev); ++ int i; ++ ++ /* Turn the LEDs off on driver removal. */ ++ for (i = 0 ; leds->led[i] ; i++) ++ mt6323_led_hw_off(&leds->led[i]->cdev); ++ ++ regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0, ++ MT6323_RG_DRV_32K_CK_PDN_MASK, ++ MT6323_RG_DRV_32K_CK_PDN); ++ ++ mutex_destroy(&leds->lock); ++ ++ return 0; ++} ++ ++static const struct of_device_id mt6323_led_dt_match[] = { ++ { .compatible = "mediatek,mt6323-led" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mt6323_led_dt_match); ++ ++static struct platform_driver mt6323_led_driver = { ++ .probe = mt6323_led_probe, ++ .remove = mt6323_led_remove, ++ .driver = { ++ .name = "mt6323-led", ++ .of_match_table = mt6323_led_dt_match, ++ }, ++}; ++ ++module_platform_driver(mt6323_led_driver); ++ ++MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC"); ++MODULE_AUTHOR("Sean Wang "); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch b/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch new file mode 100644 index 0000000000..701dcec962 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0088-pmic-led3.patch @@ -0,0 +1,44 @@ +From patchwork Mon Mar 20 06:47:27 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v6, + 4/4] mfd: mt6397: Align the placement at which the mfd_cell of LED is + defined +From: sean.wang@mediatek.com +X-Patchwork-Id: 9633079 +Message-Id: <1489992447-13007-5-git-send-email-sean.wang@mediatek.com> +To: , , , + , , , + +Cc: devicetree@vger.kernel.org, keyhaede@gmail.com, + Sean Wang , linux-kernel@vger.kernel.org, + linux-mediatek@lists.infradead.org, linux-leds@vger.kernel.org, + linux-arm-kernel@lists.infradead.org +Date: Mon, 20 Mar 2017 14:47:27 +0800 + +From: Sean Wang + +Align the placement as which the mfd_cell of LED is defined as the other +members done on the structure. + +Signed-off-by: Sean Wang +Acked-by: Lee Jones +--- + drivers/mfd/mt6397-core.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c +index 8e601c8..04a601f 100644 +--- a/drivers/mfd/mt6397-core.c ++++ b/drivers/mfd/mt6397-core.c +@@ -47,8 +47,7 @@ + { + .name = "mt6323-regulator", + .of_compatible = "mediatek,mt6323-regulator" +- }, +- { ++ }, { + .name = "mt6323-led", + .of_compatible = "mediatek,mt6323-led" + }, diff --git a/target/linux/mediatek/patches-4.9/0091-dsa1.patch b/target/linux/mediatek/patches-4.9/0091-dsa1.patch new file mode 100644 index 0000000000..c9bad9362d --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0091-dsa1.patch @@ -0,0 +1,127 @@ +From patchwork Wed Mar 29 09:38:19 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [net-next,v3,1/5] dt-bindings: net: dsa: add Mediatek MT7530 binding +From: sean.wang@mediatek.com +X-Patchwork-Id: 9651093 +Message-Id: <1490780303-18598-2-git-send-email-sean.wang@mediatek.com> +To: , , + , , + , +Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, + netdev@vger.kernel.org, sean.wang@mediatek.com, + linux-kernel@vger.kernel.org, + linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net +Date: Wed, 29 Mar 2017 17:38:19 +0800 + +From: Sean Wang + +Add device-tree binding for Mediatek MT7530 switch. + +Cc: devicetree@vger.kernel.org +Signed-off-by: Sean Wang +Acked-by: Rob Herring +--- + .../devicetree/bindings/net/dsa/mt7530.txt | 92 ++++++++++++++++++++++ + 1 file changed, 92 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/dsa/mt7530.txt + +diff --git a/Documentation/devicetree/bindings/net/dsa/mt7530.txt b/Documentation/devicetree/bindings/net/dsa/mt7530.txt +new file mode 100644 +index 0000000..a9bc27b +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/dsa/mt7530.txt +@@ -0,0 +1,92 @@ ++Mediatek MT7530 Ethernet switch ++================================ ++ ++Required properties: ++ ++- compatible: Must be compatible = "mediatek,mt7530"; ++- #address-cells: Must be 1. ++- #size-cells: Must be 0. ++- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part ++ on multi-chip module belong to MT7623A has or the remotely standalone ++ chip as the function MT7623N reference board provided for. ++- core-supply: Phandle to the regulator node necessary for the core power. ++- io-supply: Phandle to the regulator node necessary for the I/O power. ++ See Documentation/devicetree/bindings/regulator/mt6323-regulator.txt ++ for details for the regulator setup on these boards. ++ ++If the property mediatek,mcm isn't defined, following property is required ++ ++- reset-gpios: Should be a gpio specifier for a reset line. ++ ++Else, following properties are required ++ ++- resets : Phandle pointing to the system reset controller with ++ line index for the ethsys. ++- reset-names : Should be set to "mcm". ++ ++Required properties for the child nodes within ports container: ++ ++- reg: Port address described must be 6 for CPU port and from 0 to 5 for ++ user ports. ++- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled ++ "cpu". ++ ++See Documentation/devicetree/bindings/dsa/dsa.txt for a list of additional ++required, optional properties and how the integrated switch subnodes must ++be specified. ++ ++Example: ++ ++ &mdio0 { ++ switch@0 { ++ compatible = "mediatek,mt7530"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ core-supply = <&mt6323_vpa_reg>; ++ io-supply = <&mt6323_vemc3v3_reg>; ++ reset-gpios = <&pio 33 0>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ port@0 { ++ reg = <0>; ++ label = "lan0"; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "lan1"; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "lan2"; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "lan3"; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "wan"; ++ }; ++ ++ port@6 { ++ reg = <6>; ++ label = "cpu"; ++ ethernet = <&gmac0>; ++ phy-mode = "trgmii"; ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ }; ++ }; ++ }; diff --git a/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch b/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch new file mode 100644 index 0000000000..5ae90e353f --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0091-net-next-mediatek-fix-DQL-support.patch @@ -0,0 +1,95 @@ +From 81cdbda2a08375b9d5915567d2210bf2433e7332 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Sat, 23 Apr 2016 11:57:21 +0200 +Subject: [PATCH 081/102] net-next: mediatek: fix DQL support + +The MTK ethernet core has 2 MACs both sitting on the same DMA ring. The +current code will assign the TX traffic of each MAC to its own DQL. This +results in the amount of data, that DQL says is in the queue incorrect. As +the data from multiple devices is infact enqueued. This makes any decision +based on these value non deterministic. Fix this by tracking all TX +traffic, regardless of the MAC it belongs to in the DQL of all devices +using the DMA. + +Signed-off-by: John Crispin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 33 ++++++++++++++++----------- + 1 file changed, 20 insertions(+), 13 deletions(-) + +Index: linux-4.9.14/drivers/net/ethernet/mediatek/mtk_eth_soc.c +=================================================================== +--- linux-4.9.14.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ linux-4.9.14/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -706,7 +706,16 @@ static int mtk_tx_map(struct sk_buff *sk + WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | + (!nr_frags * TX_DMA_LS0))); + +- netdev_sent_queue(dev, skb->len); ++ /* we have a single DMA ring so BQL needs to be updated for all devices ++ * sitting on this ring ++ */ ++ for (i = 0; i < MTK_MAC_COUNT; i++) { ++ if (!eth->netdev[i]) ++ continue; ++ ++ netdev_sent_queue(eth->netdev[i], skb->len); ++ } ++ + skb_tx_timestamp(skb); + + ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); +@@ -998,21 +1007,18 @@ static int mtk_poll_tx(struct mtk_eth *e + struct mtk_tx_dma *desc; + struct sk_buff *skb; + struct mtk_tx_buf *tx_buf; +- unsigned int done[MTK_MAX_DEVS]; +- unsigned int bytes[MTK_MAX_DEVS]; ++ int total = 0, done = 0; ++ unsigned int bytes = 0; + u32 cpu, dma; + static int condition; +- int total = 0, i; +- +- memset(done, 0, sizeof(done)); +- memset(bytes, 0, sizeof(bytes)); ++ int i; + + cpu = mtk_r32(eth, MTK_QTX_CRX_PTR); + dma = mtk_r32(eth, MTK_QTX_DRX_PTR); + + desc = mtk_qdma_phys_to_virt(ring, cpu); + +- while ((cpu != dma) && budget) { ++ while ((cpu != dma) && done < budget) { + u32 next_cpu = desc->txd2; + int mac; + +@@ -1032,9 +1038,8 @@ static int mtk_poll_tx(struct mtk_eth *e + } + + if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { +- bytes[mac] += skb->len; +- done[mac]++; +- budget--; ++ bytes += skb->len; ++ done++; + } + mtk_tx_unmap(eth, tx_buf); + +@@ -1046,11 +1051,13 @@ static int mtk_poll_tx(struct mtk_eth *e + + mtk_w32(eth, cpu, MTK_QTX_CRX_PTR); + ++ /* we have a single DMA ring so BQL needs to be updated for all devices ++ * sitting on this ring ++ */ + for (i = 0; i < MTK_MAC_COUNT; i++) { +- if (!eth->netdev[i] || !done[i]) ++ if (!eth->netdev[i]) + continue; +- netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); +- total += done[i]; ++ netdev_completed_queue(eth->netdev[i], done, bytes); + } + + if (mtk_queue_stopped(eth) && diff --git a/target/linux/mediatek/patches-4.9/0092-dsa2.patch b/target/linux/mediatek/patches-4.9/0092-dsa2.patch new file mode 100644 index 0000000000..84e5cb43f7 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0092-dsa2.patch @@ -0,0 +1,219 @@ +From patchwork Wed Mar 29 09:38:20 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [net-next,v3,2/5] net-next: dsa: add Mediatek tag RX/TX handler +From: sean.wang@mediatek.com +X-Patchwork-Id: 9651099 +Message-Id: <1490780303-18598-3-git-send-email-sean.wang@mediatek.com> +To: , , + , , + , +Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, + netdev@vger.kernel.org, sean.wang@mediatek.com, + linux-kernel@vger.kernel.org, + linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net +Date: Wed, 29 Mar 2017 17:38:20 +0800 + +From: Sean Wang + +Add the support for the 4-bytes tag for DSA port distinguishing inserted +allowing receiving and transmitting the packet via the particular port. +The tag is being added after the source MAC address in the ethernet +header. + +Signed-off-by: Sean Wang +Signed-off-by: Landen Chao +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +--- + include/net/dsa.h | 1 + + net/dsa/Kconfig | 2 + + net/dsa/Makefile | 1 + + net/dsa/dsa.c | 3 ++ + net/dsa/dsa_priv.h | 3 ++ + net/dsa/tag_mtk.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 6 files changed, 127 insertions(+) + create mode 100644 net/dsa/tag_mtk.c + +diff --git a/include/net/dsa.h b/include/net/dsa.h +index 4e13e69..3276547 100644 +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -31,6 +31,7 @@ enum dsa_tag_protocol { + DSA_TAG_PROTO_EDSA, + DSA_TAG_PROTO_BRCM, + DSA_TAG_PROTO_QCA, ++ DSA_TAG_PROTO_MTK, + DSA_TAG_LAST, /* MUST BE LAST */ + }; + +diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig +index 9649238..d78789b 100644 +--- a/net/dsa/Kconfig ++++ b/net/dsa/Kconfig +@@ -31,4 +31,6 @@ config NET_DSA_TAG_TRAILER + config NET_DSA_TAG_QCA + bool + ++config NET_DSA_TAG_MTK ++ bool + endif +diff --git a/net/dsa/Makefile b/net/dsa/Makefile +index 31d3437..9b1d478 100644 +--- a/net/dsa/Makefile ++++ b/net/dsa/Makefile +@@ -8,3 +8,4 @@ dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o + dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o + dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o + dsa_core-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o ++dsa_core-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o +diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c +index b6d4f6a..617f736 100644 +--- a/net/dsa/dsa.c ++++ b/net/dsa/dsa.c +@@ -53,6 +53,9 @@ static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb, + #ifdef CONFIG_NET_DSA_TAG_QCA + [DSA_TAG_PROTO_QCA] = &qca_netdev_ops, + #endif ++#ifdef CONFIG_NET_DSA_TAG_MTK ++ [DSA_TAG_PROTO_MTK] = &mtk_netdev_ops, ++#endif + [DSA_TAG_PROTO_NONE] = &none_ops, + }; + +diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h +index 0706a51..2a31399 100644 +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -85,4 +85,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent, + /* tag_qca.c */ + extern const struct dsa_device_ops qca_netdev_ops; + ++/* tag_mtk.c */ ++extern const struct dsa_device_ops mtk_netdev_ops; ++ + #endif +diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c +new file mode 100644 +index 0000000..833a9d6 +--- /dev/null ++++ b/net/dsa/tag_mtk.c +@@ -0,0 +1,117 @@ ++/* ++ * Mediatek DSA Tag support ++ * Copyright (C) 2017 Landen Chao ++ * Sean Wang ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include "dsa_priv.h" ++ ++#define MTK_HDR_LEN 4 ++#define MTK_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0) ++#define MTK_HDR_XMIT_DP_BIT_MASK GENMASK(5, 0) ++ ++static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ struct dsa_slave_priv *p = netdev_priv(dev); ++ u8 *mtk_tag; ++ ++ if (skb_cow_head(skb, MTK_HDR_LEN) < 0) ++ goto out_free; ++ ++ skb_push(skb, MTK_HDR_LEN); ++ ++ memmove(skb->data, skb->data + MTK_HDR_LEN, 2 * ETH_ALEN); ++ ++ /* Build the tag after the MAC Source Address */ ++ mtk_tag = skb->data + 2 * ETH_ALEN; ++ mtk_tag[0] = 0; ++ mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK; ++ mtk_tag[2] = 0; ++ mtk_tag[3] = 0; ++ ++ return skb; ++ ++out_free: ++ kfree_skb(skb); ++ return NULL; ++} ++ ++static int mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev, ++ struct packet_type *pt, struct net_device *orig_dev) ++{ ++ struct dsa_switch_tree *dst = dev->dsa_ptr; ++ struct dsa_switch *ds; ++ int port; ++ __be16 *phdr, hdr; ++ ++ if (unlikely(!dst)) ++ goto out_drop; ++ ++ skb = skb_unshare(skb, GFP_ATOMIC); ++ if (!skb) ++ goto out; ++ ++ if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN))) ++ goto out_drop; ++ ++ /* The MTK header is added by the switch between src addr ++ * and ethertype at this point, skb->data points to 2 bytes ++ * after src addr so header should be 2 bytes right before. ++ */ ++ phdr = (__be16 *)(skb->data - 2); ++ hdr = ntohs(*phdr); ++ ++ /* Remove MTK tag and recalculate checksum. */ ++ skb_pull_rcsum(skb, MTK_HDR_LEN); ++ ++ memmove(skb->data - ETH_HLEN, ++ skb->data - ETH_HLEN - MTK_HDR_LEN, ++ 2 * ETH_ALEN); ++ ++ /* This protocol doesn't support cascading multiple ++ * switches so it's safe to assume the switch is first ++ * in the tree. ++ */ ++ ds = dst->ds[0]; ++ if (!ds) ++ goto out_drop; ++ ++ /* Get source port information */ ++ port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK); ++ if (!ds->ports[port].netdev) ++ goto out_drop; ++ ++ /* Update skb & forward the frame accordingly */ ++ skb_push(skb, ETH_HLEN); ++ ++ skb->pkt_type = PACKET_HOST; ++ skb->dev = ds->ports[port].netdev; ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ skb->dev->stats.rx_packets++; ++ skb->dev->stats.rx_bytes += skb->len; ++ ++ netif_receive_skb(skb); ++ ++ return 0; ++ ++out_drop: ++ kfree_skb(skb); ++out: ++ return 0; ++} ++ ++const struct dsa_device_ops mtk_netdev_ops = { ++ .xmit = mtk_tag_xmit, ++ .rcv = mtk_tag_rcv, ++}; diff --git a/target/linux/mediatek/patches-4.9/0092-dsa3.patch b/target/linux/mediatek/patches-4.9/0092-dsa3.patch new file mode 100644 index 0000000000..7c4dc4f35c --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0092-dsa3.patch @@ -0,0 +1,67 @@ +From patchwork Wed Mar 29 09:38:21 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [net-next, v3, + 3/5] net-next: ethernet: mediatek: add CDM able to recognize the tag + for DSA +From: sean.wang@mediatek.com +X-Patchwork-Id: 9651091 +Message-Id: <1490780303-18598-4-git-send-email-sean.wang@mediatek.com> +To: , , + , , + , +Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, + netdev@vger.kernel.org, sean.wang@mediatek.com, + linux-kernel@vger.kernel.org, + linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net +Date: Wed, 29 Mar 2017 17:38:21 +0800 + +From: Sean Wang + +The patch adds the setup for allowing CDM can recognize these packets with +carrying port-distinguishing tag. Otherwise, these tagging packets will be +handled incorrectly by CDM. The setup is also working out for general +untag packets as well. + +Signed-off-by: Sean Wang +Signed-off-by: Landen Chao +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 ++++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++++ + 2 files changed, 10 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 9e75768..c21ed99 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1846,6 +1846,12 @@ static int mtk_hw_init(struct mtk_eth *eth) + /* GE2, Force 1000M/FD, FC ON */ + mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(1)); + ++ /* Indicates CDM to parse the MTK special tag from CPU ++ * which also is working out for untag packets. ++ */ ++ val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); ++ mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); ++ + /* Enable RX VLan Offloading */ + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +index 99b1c8e..996024d 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -70,6 +70,10 @@ + /* Frame Engine Interrupt Grouping Register */ + #define MTK_FE_INT_GRP 0x20 + ++/* CDMP Ingress Control Register */ ++#define MTK_CDMQ_IG_CTRL 0x1400 ++#define MTK_CDMQ_STAG_EN BIT(0) ++ + /* CDMP Exgress Control Register */ + #define MTK_CDMP_EG_CTRL 0x404 + diff --git a/target/linux/mediatek/patches-4.9/0092-dsa4.patch b/target/linux/mediatek/patches-4.9/0092-dsa4.patch new file mode 100644 index 0000000000..d67b4a9e61 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0092-dsa4.patch @@ -0,0 +1,46 @@ +From patchwork Wed Mar 29 09:38:22 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [net-next, v3, + 4/5] net-next: ethernet: mediatek: add device_node of GMAC pointing + into the netdev instance +From: sean.wang@mediatek.com +X-Patchwork-Id: 9651097 +Message-Id: <1490780303-18598-5-git-send-email-sean.wang@mediatek.com> +To: , , + , , + , +Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, + netdev@vger.kernel.org, sean.wang@mediatek.com, + linux-kernel@vger.kernel.org, + linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net +Date: Wed, 29 Mar 2017 17:38:22 +0800 + +From: Sean Wang + +the patch adds the setup of the corresponding device node of GMAC into the +netdev instance which could allow other modules such as DSA to find the +instance through the node in dt-bindings using of_find_net_device_by_node() +call. + +Signed-off-by: Sean Wang +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index c21ed99..84b09a4 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2323,6 +2323,8 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) + eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops; + + eth->netdev[id]->irq = eth->irq[0]; ++ eth->netdev[id]->dev.of_node = np; ++ + return 0; + + free_netdev: diff --git a/target/linux/mediatek/patches-4.9/0092-dsa5.patch b/target/linux/mediatek/patches-4.9/0092-dsa5.patch new file mode 100644 index 0000000000..6c101377c3 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0092-dsa5.patch @@ -0,0 +1,1608 @@ +From patchwork Wed Mar 29 09:38:23 2017 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [net-next, v3, + 5/5] net-next: dsa: add dsa support for Mediatek MT7530 switch +From: sean.wang@mediatek.com +X-Patchwork-Id: 9651095 +Message-Id: <1490780303-18598-6-git-send-email-sean.wang@mediatek.com> +To: , , + , , + , +Cc: devicetree@vger.kernel.org, Landen.Chao@mediatek.com, keyhaede@gmail.com, + netdev@vger.kernel.org, sean.wang@mediatek.com, + linux-kernel@vger.kernel.org, + linux-mediatek@lists.infradead.org, objelf@gmail.com, davem@davemloft.net +Date: Wed, 29 Mar 2017 17:38:23 +0800 + +From: Sean Wang + +MT7530 is a 7-ports Gigabit Ethernet Switch that could be found on +Mediatek router platforms such as MT7623A or MT7623N platform which +includes 7-port Gigabit Ethernet MAC and 5-port Gigabit Ethernet PHY. +Among these ports, The port from 0 to 4 are the user ports connecting +with the remote devices while the port 5 and 6 are the CPU ports +connecting into Mediatek Ethernet GMAC. + +For port 6, it can communicate with the CPU via Mediatek Ethernet GMAC +through either the TRGMII or RGMII which could be controlled by phy-mode +in the dt-bindings to specify which mode is preferred to use. And for +port 5, only RGMII can be specified. However, currently, only port 6 is +being supported in this DSA driver. + +The driver is made with the reference to qca8k and other existing DSA +driver. The most of the essential callbacks of the DSA are already +support in the driver, including tag insert for user port distinguishing, +port control, bridge offloading, STP setup and ethtool operation to allow +DSA to model each user port into a standalone netdevice as the other DSA +driver had done. + +Signed-off-by: Sean Wang +Signed-off-by: Landen Chao +--- + drivers/net/dsa/Kconfig | 8 + + drivers/net/dsa/Makefile | 2 +- + drivers/net/dsa/mt7530.c | 1126 ++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/mt7530.h | 390 ++++++++++++++++ + 4 files changed, 1525 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/dsa/mt7530.c + create mode 100644 drivers/net/dsa/mt7530.h + +diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig +index 0659846..5b322b4 100644 +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -34,4 +34,12 @@ config NET_DSA_QCA8K + This enables support for the Qualcomm Atheros QCA8K Ethernet + switch chips. + ++config NET_DSA_MT7530 ++ tristate "Mediatek MT7530 Ethernet switch support" ++ depends on NET_DSA ++ select NET_DSA_TAG_MTK ++ ---help--- ++ This enables support for the Mediatek MT7530 Ethernet switch ++ chip. ++ + endmenu +diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile +index a3c9416..8e629c1 100644 +--- a/drivers/net/dsa/Makefile ++++ b/drivers/net/dsa/Makefile +@@ -2,6 +2,6 @@ obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o + obj-$(CONFIG_NET_DSA_BCM_SF2) += bcm-sf2.o + bcm-sf2-objs := bcm_sf2.o bcm_sf2_cfp.o + obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o +- ++obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o + obj-y += b53/ + obj-y += mv88e6xxx/ +diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c +new file mode 100644 +index 0000000..ad2e6f8 +--- /dev/null ++++ b/drivers/net/dsa/mt7530.c +@@ -0,0 +1,1126 @@ ++/* ++ * Mediatek MT7530 DSA Switch driver ++ * Copyright (C) 2017 Sean Wang ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mt7530.h" ++ ++/* String, offset, and register size in bytes if different from 4 bytes */ ++static const struct mt7530_mib_desc mt7530_mib[] = { ++ MIB_DESC(1, 0x00, "TxDrop"), ++ MIB_DESC(1, 0x04, "TxCrcErr"), ++ MIB_DESC(1, 0x08, "TxUnicast"), ++ MIB_DESC(1, 0x0c, "TxMulticast"), ++ MIB_DESC(1, 0x10, "TxBroadcast"), ++ MIB_DESC(1, 0x14, "TxCollision"), ++ MIB_DESC(1, 0x18, "TxSingleCollision"), ++ MIB_DESC(1, 0x1c, "TxMultipleCollision"), ++ MIB_DESC(1, 0x20, "TxDeferred"), ++ MIB_DESC(1, 0x24, "TxLateCollision"), ++ MIB_DESC(1, 0x28, "TxExcessiveCollistion"), ++ MIB_DESC(1, 0x2c, "TxPause"), ++ MIB_DESC(1, 0x30, "TxPktSz64"), ++ MIB_DESC(1, 0x34, "TxPktSz65To127"), ++ MIB_DESC(1, 0x38, "TxPktSz128To255"), ++ MIB_DESC(1, 0x3c, "TxPktSz256To511"), ++ MIB_DESC(1, 0x40, "TxPktSz512To1023"), ++ MIB_DESC(1, 0x44, "Tx1024ToMax"), ++ MIB_DESC(2, 0x48, "TxBytes"), ++ MIB_DESC(1, 0x60, "RxDrop"), ++ MIB_DESC(1, 0x64, "RxFiltering"), ++ MIB_DESC(1, 0x6c, "RxMulticast"), ++ MIB_DESC(1, 0x70, "RxBroadcast"), ++ MIB_DESC(1, 0x74, "RxAlignErr"), ++ MIB_DESC(1, 0x78, "RxCrcErr"), ++ MIB_DESC(1, 0x7c, "RxUnderSizeErr"), ++ MIB_DESC(1, 0x80, "RxFragErr"), ++ MIB_DESC(1, 0x84, "RxOverSzErr"), ++ MIB_DESC(1, 0x88, "RxJabberErr"), ++ MIB_DESC(1, 0x8c, "RxPause"), ++ MIB_DESC(1, 0x90, "RxPktSz64"), ++ MIB_DESC(1, 0x94, "RxPktSz65To127"), ++ MIB_DESC(1, 0x98, "RxPktSz128To255"), ++ MIB_DESC(1, 0x9c, "RxPktSz256To511"), ++ MIB_DESC(1, 0xa0, "RxPktSz512To1023"), ++ MIB_DESC(1, 0xa4, "RxPktSz1024ToMax"), ++ MIB_DESC(2, 0xa8, "RxBytes"), ++ MIB_DESC(1, 0xb0, "RxCtrlDrop"), ++ MIB_DESC(1, 0xb4, "RxIngressDrop"), ++ MIB_DESC(1, 0xb8, "RxArlDrop"), ++}; ++ ++static struct mt7530_priv *lpriv; ++static void mt7530_port_disable(struct dsa_switch *ds, int port, ++ struct phy_device *phy); ++static int mt7530_cpu_port_enable(struct mt7530_priv *priv, ++ int port); ++ ++static int ++mt7623_trgmii_write(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ int ret; ++ ++ ret = regmap_write(priv->ethernet, TRGMII_BASE(reg), val); ++ if (ret < 0) ++ dev_err(priv->dev, ++ "failed to priv write register\n"); ++ return ret; ++} ++ ++static u32 ++mt7623_trgmii_read(struct mt7530_priv *priv, u32 reg) ++{ ++ int ret; ++ u32 val; ++ ++ ret = regmap_read(priv->ethernet, TRGMII_BASE(reg), &val); ++ if (ret < 0) { ++ dev_err(priv->dev, ++ "failed to priv read register\n"); ++ return ret; ++ } ++ ++ return val; ++} ++ ++static void ++mt7623_trgmii_rmw(struct mt7530_priv *priv, u32 reg, ++ u32 mask, u32 set) ++{ ++ u32 val; ++ ++ val = mt7623_trgmii_read(priv, reg); ++ val &= ~mask; ++ val |= set; ++ mt7623_trgmii_write(priv, reg, val); ++} ++ ++static void ++mt7623_trgmii_set(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ mt7623_trgmii_rmw(priv, reg, 0, val); ++} ++ ++static void ++mt7623_trgmii_clear(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ mt7623_trgmii_rmw(priv, reg, val, 0); ++} ++ ++static int ++core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad) ++{ ++ struct mii_bus *bus = priv->bus; ++ int value, ret; ++ ++ /* Write the desired MMD Devad */ ++ ret = bus->write(bus, 0, MII_MMD_CTRL, devad); ++ if (ret < 0) ++ goto err; ++ ++ /* Write the desired MMD register address */ ++ ret = bus->write(bus, 0, MII_MMD_DATA, prtad); ++ if (ret < 0) ++ goto err; ++ ++ /* Select the Function : DATA with no post increment */ ++ ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); ++ if (ret < 0) ++ goto err; ++ ++ /* Read the content of the MMD's selected register */ ++ value = bus->read(bus, 0, MII_MMD_DATA); ++ ++ return value; ++err: ++ dev_err(&bus->dev, "failed to read mmd register\n"); ++ ++ return ret; ++} ++ ++static int ++core_write_mmd_indirect(struct mt7530_priv *priv, int prtad, ++ int devad, u32 data) ++{ ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ /* Write the desired MMD Devad */ ++ ret = bus->write(bus, 0, MII_MMD_CTRL, devad); ++ if (ret < 0) ++ goto err; ++ ++ /* Write the desired MMD register address */ ++ ret = bus->write(bus, 0, MII_MMD_DATA, prtad); ++ if (ret < 0) ++ goto err; ++ ++ /* Select the Function : DATA with no post increment */ ++ ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); ++ if (ret < 0) ++ goto err; ++ ++ /* Write the data into MMD's selected register */ ++ ret = bus->write(bus, 0, MII_MMD_DATA, data); ++err: ++ if (ret < 0) ++ dev_err(&bus->dev, ++ "failed to write mmd register\n"); ++ return ret; ++} ++ ++static void ++core_write(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ struct mii_bus *bus = priv->bus; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val); ++ ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static void ++core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set) ++{ ++ struct mii_bus *bus = priv->bus; ++ u32 val; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2); ++ val &= ~mask; ++ val |= set; ++ core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val); ++ ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static void ++core_set(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ core_rmw(priv, reg, 0, val); ++} ++ ++static void ++core_clear(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ core_rmw(priv, reg, val, 0); ++} ++ ++static int ++mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ struct mii_bus *bus = priv->bus; ++ u16 page, r, lo, hi; ++ int ret; ++ ++ page = (reg >> 6) & 0x3ff; ++ r = (reg >> 2) & 0xf; ++ lo = val & 0xffff; ++ hi = val >> 16; ++ ++ /* MT7530 uses 31 as the pseudo port */ ++ ret = bus->write(bus, 0x1f, 0x1f, page); ++ if (ret < 0) ++ goto err; ++ ++ ret = bus->write(bus, 0x1f, r, lo); ++ if (ret < 0) ++ goto err; ++ ++ ret = bus->write(bus, 0x1f, 0x10, hi); ++err: ++ if (ret < 0) ++ dev_err(&bus->dev, ++ "failed to write mt7530 register\n"); ++ return ret; ++} ++ ++static u32 ++mt7530_mii_read(struct mt7530_priv *priv, u32 reg) ++{ ++ struct mii_bus *bus = priv->bus; ++ u16 page, r, lo, hi; ++ int ret; ++ ++ page = (reg >> 6) & 0x3ff; ++ r = (reg >> 2) & 0xf; ++ ++ /* MT7530 uses 31 as the pseudo port */ ++ ret = bus->write(bus, 0x1f, 0x1f, page); ++ if (ret < 0) { ++ dev_err(&bus->dev, ++ "failed to read mt7530 register\n"); ++ return ret; ++ } ++ ++ lo = bus->read(bus, 0x1f, r); ++ hi = bus->read(bus, 0x1f, 0x10); ++ ++ return (hi << 16) | (lo & 0xffff); ++} ++ ++static void ++mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ struct mii_bus *bus = priv->bus; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ mt7530_mii_write(priv, reg, val); ++ ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static u32 ++_mt7530_read(u32 reg) ++{ ++ struct mt7530_priv *priv = lpriv; ++ struct mii_bus *bus = priv->bus; ++ u32 val; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ val = mt7530_mii_read(priv, reg); ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ return val; ++} ++ ++static u32 ++mt7530_read(struct mt7530_priv *priv, u32 reg) ++{ ++ return _mt7530_read(reg); ++} ++ ++static void ++mt7530_rmw(struct mt7530_priv *priv, u32 reg, ++ u32 mask, u32 set) ++{ ++ struct mii_bus *bus = priv->bus; ++ u32 val; ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ val = mt7530_mii_read(priv, reg); ++ val &= ~mask; ++ val |= set; ++ mt7530_mii_write(priv, reg, val); ++ ++ mutex_unlock(&bus->mdio_lock); ++} ++ ++static void ++mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ mt7530_rmw(priv, reg, 0, val); ++} ++ ++static void ++mt7530_clear(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ mt7530_rmw(priv, reg, val, 0); ++} ++ ++static int ++mt7530_fdb_cmd(struct mt7530_priv *priv, enum mt7530_fdb_cmd cmd, u32 *rsp) ++{ ++ u32 val; ++ int ret; ++ ++ /* Set the command operating upon the MAC address entries */ ++ val = ATC_BUSY | ATC_MAT(0) | cmd; ++ mt7530_write(priv, MT7530_ATC, val); ++ ++ ret = readx_poll_timeout(_mt7530_read, MT7530_ATC, val, ++ !(val & ATC_BUSY), 20, 20000); ++ if (ret < 0) { ++ dev_err(priv->dev, "reset timeout\n"); ++ return ret; ++ } ++ ++ /* Additional sanity for read command if the specified ++ * entry is invalid ++ */ ++ val = mt7530_read(priv, MT7530_ATC); ++ if ((cmd == MT7530_FDB_READ) && (val & ATC_INVALID)) ++ return -EINVAL; ++ ++ if (rsp) ++ *rsp = val; ++ ++ return 0; ++} ++ ++static void ++mt7530_fdb_read(struct mt7530_priv *priv, struct mt7530_fdb *fdb) ++{ ++ u32 reg[3]; ++ int i; ++ ++ /* Read from ARL table into an array */ ++ for (i = 0; i < 3; i++) { ++ reg[i] = mt7530_read(priv, MT7530_TSRA1 + (i * 4)); ++ ++ dev_dbg(priv->dev, "%s(%d) reg[%d]=0x%x\n", ++ __func__, __LINE__, i, reg[i]); ++ } ++ ++ fdb->vid = (reg[1] >> CVID) & CVID_MASK; ++ fdb->aging = (reg[2] >> AGE_TIMER) & AGE_TIMER_MASK; ++ fdb->port_mask = (reg[2] >> PORT_MAP) & PORT_MAP_MASK; ++ fdb->mac[0] = (reg[0] >> MAC_BYTE_0) & MAC_BYTE_MASK; ++ fdb->mac[1] = (reg[0] >> MAC_BYTE_1) & MAC_BYTE_MASK; ++ fdb->mac[2] = (reg[0] >> MAC_BYTE_2) & MAC_BYTE_MASK; ++ fdb->mac[3] = (reg[0] >> MAC_BYTE_3) & MAC_BYTE_MASK; ++ fdb->mac[4] = (reg[1] >> MAC_BYTE_4) & MAC_BYTE_MASK; ++ fdb->mac[5] = (reg[1] >> MAC_BYTE_5) & MAC_BYTE_MASK; ++ fdb->noarp = ((reg[2] >> ENT_STATUS) & ENT_STATUS_MASK) == STATIC_ENT; ++} ++ ++static void ++mt7530_fdb_write(struct mt7530_priv *priv, u16 vid, ++ u8 port_mask, const u8 *mac, ++ u8 aging, u8 type) ++{ ++ u32 reg[3] = { 0 }; ++ int i; ++ ++ reg[1] |= vid & CVID_MASK; ++ reg[2] |= (aging & AGE_TIMER_MASK) << AGE_TIMER; ++ reg[2] |= (port_mask & PORT_MAP_MASK) << PORT_MAP; ++ /* STATIC_ENT indicate that entry is static wouldn't ++ * be aged out and STATIC_EMP specified as erasing an ++ * entry ++ */ ++ reg[2] |= (type & ENT_STATUS_MASK) << ENT_STATUS; ++ reg[1] |= mac[5] << MAC_BYTE_5; ++ reg[1] |= mac[4] << MAC_BYTE_4; ++ reg[0] |= mac[3] << MAC_BYTE_3; ++ reg[0] |= mac[2] << MAC_BYTE_2; ++ reg[0] |= mac[1] << MAC_BYTE_1; ++ reg[0] |= mac[0] << MAC_BYTE_0; ++ ++ /* Write array into the ARL table */ ++ for (i = 0; i < 3; i++) ++ mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]); ++} ++ ++static int ++mt7530_pad_clk_setup(struct dsa_switch *ds, int mode) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u32 ncpo1, ssc_delta, trgint, i; ++ ++ switch (mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ trgint = 0; ++ ncpo1 = 0x0c80; ++ ssc_delta = 0x87; ++ break; ++ case PHY_INTERFACE_MODE_TRGMII: ++ trgint = 1; ++ ncpo1 = 0x1400; ++ ssc_delta = 0x57; ++ break; ++ default: ++ dev_err(priv->dev, "xMII mode %d not supported\n", mode); ++ return -EINVAL; ++ } ++ ++ mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, ++ P6_INTF_MODE(trgint)); ++ ++ /* Lower Tx Driving for TRGMII path */ ++ for (i = 0 ; i < NUM_TRGMII_CTRL ; i++) ++ mt7530_write(priv, MT7530_TRGMII_TD_ODT(i), ++ TD_DM_DRVP(8) | TD_DM_DRVN(8)); ++ ++ /* Setup core clock for MT7530 */ ++ if (!trgint) { ++ /* Disable MT7530 core clock */ ++ core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); ++ ++ /* Disable PLL, since phy_device has not yet been created ++ * provided for phy_[read,write]_mmd_indirect is called, we ++ * provide our own core_write_mmd_indirect to complete this ++ * function. ++ */ ++ core_write_mmd_indirect(priv, ++ CORE_GSWPLL_GRP1, ++ MDIO_MMD_VEND2, ++ 0); ++ ++ /* Set core clock into 500Mhz */ ++ core_write(priv, CORE_GSWPLL_GRP2, ++ RG_GSWPLL_POSDIV_500M(1) | ++ RG_GSWPLL_FBKDIV_500M(25)); ++ ++ /* Enable PLL */ ++ core_write(priv, CORE_GSWPLL_GRP1, ++ RG_GSWPLL_EN_PRE | ++ RG_GSWPLL_POSDIV_200M(2) | ++ RG_GSWPLL_FBKDIV_200M(32)); ++ ++ /* Enable MT7530 core clock */ ++ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); ++ } ++ ++ /* Setup the MT7530 TRGMII Tx Clock */ ++ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); ++ core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1)); ++ core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0)); ++ core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta)); ++ core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta)); ++ core_write(priv, CORE_PLL_GROUP4, ++ RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN | ++ RG_SYSPLL_BIAS_LPF_EN); ++ core_write(priv, CORE_PLL_GROUP2, ++ RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | ++ RG_SYSPLL_POSDIV(1)); ++ core_write(priv, CORE_PLL_GROUP7, ++ RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) | ++ RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); ++ core_set(priv, CORE_TRGMII_GSW_CLK_CG, ++ REG_GSWCK_EN | REG_TRGMIICK_EN); ++ ++ if (!trgint) ++ for (i = 0 ; i < NUM_TRGMII_CTRL; i++) ++ mt7530_rmw(priv, MT7530_TRGMII_RD(i), ++ RD_TAP_MASK, RD_TAP(16)); ++ else ++ mt7623_trgmii_set(priv, GSW_INTF_MODE, INTF_MODE_TRGMII); ++ ++ return 0; ++} ++ ++static int ++mt7623_pad_clk_setup(struct dsa_switch *ds) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ int i; ++ ++ for (i = 0 ; i < NUM_TRGMII_CTRL; i++) ++ mt7623_trgmii_write(priv, GSW_TRGMII_TD_ODT(i), ++ TD_DM_DRVP(8) | TD_DM_DRVN(8)); ++ ++ mt7623_trgmii_set(priv, GSW_TRGMII_RCK_CTRL, RX_RST | RXC_DQSISEL); ++ mt7623_trgmii_clear(priv, GSW_TRGMII_RCK_CTRL, RX_RST); ++ ++ return 0; ++} ++ ++static void ++mt7530_mib_reset(struct dsa_switch *ds) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_FLUSH); ++ mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE); ++} ++ ++static void ++mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable) ++{ ++ u32 mask = PMCR_TX_EN | PMCR_RX_EN; ++ ++ if (enable) ++ mt7530_set(priv, MT7530_PMCR_P(port), mask); ++ else ++ mt7530_clear(priv, MT7530_PMCR_P(port), mask); ++} ++ ++static int ++mt7530_setup(struct dsa_switch *ds) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ int ret, i; ++ u32 id, val; ++ struct device_node *dn; ++ ++ /* The parent node of master_netdev which holds the common system ++ * controller also is the container for two GMACs nodes representing ++ * as two netdev instances. ++ */ ++ dn = ds->master_netdev->dev.of_node->parent; ++ priv->ethernet = syscon_node_to_regmap(dn); ++ if (IS_ERR(priv->ethernet)) ++ return PTR_ERR(priv->ethernet); ++ ++ regulator_set_voltage(priv->core_pwr, 1000000, 1000000); ++ ret = regulator_enable(priv->core_pwr); ++ if (ret < 0) { ++ dev_err(priv->dev, ++ "Failed to enable core power: %d\n", ret); ++ return ret; ++ } ++ ++ regulator_set_voltage(priv->io_pwr, 3300000, 3300000); ++ ret = regulator_enable(priv->io_pwr); ++ if (ret < 0) { ++ dev_err(priv->dev, "Failed to enable io pwr: %d\n", ++ ret); ++ return ret; ++ } ++ ++ /* Reset whole chip through gpio pin or memory-mapped registers for ++ * different type of hardware ++ */ ++ if (priv->mcm) { ++ reset_control_assert(priv->rstc); ++ usleep_range(1000, 1100); ++ reset_control_deassert(priv->rstc); ++ } else { ++ gpiod_set_value_cansleep(priv->reset, 0); ++ usleep_range(1000, 1100); ++ gpiod_set_value_cansleep(priv->reset, 1); ++ } ++ ++ /* Waiting for MT7530 got to stable */ ++ ret = readx_poll_timeout(_mt7530_read, MT7530_HWTRAP, val, val != 0, ++ 20, 1000000); ++ if (ret < 0) { ++ dev_err(priv->dev, "reset timeout\n"); ++ return ret; ++ } ++ ++ id = mt7530_read(priv, MT7530_CREV); ++ id >>= CHIP_NAME_SHIFT; ++ if (id != MT7530_ID) { ++ dev_err(priv->dev, "chip %x can't be supported\n", id); ++ return -ENODEV; ++ } ++ ++ /* Reset the switch through internal reset */ ++ mt7530_write(priv, MT7530_SYS_CTRL, ++ SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST | ++ SYS_CTRL_REG_RST); ++ ++ /* Enable Port 6 only; P5 as GMAC5 which currently is not supported */ ++ val = mt7530_read(priv, MT7530_MHWTRAP); ++ val &= ~MHWTRAP_P6_DIS & ~MHWTRAP_PHY_ACCESS; ++ val |= MHWTRAP_MANUAL; ++ mt7530_write(priv, MT7530_MHWTRAP, val); ++ ++ /* Enable and reset MIB counters */ ++ mt7530_mib_reset(ds); ++ ++ mt7530_clear(priv, MT7530_MFC, UNU_FFP_MASK); ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ /* Disable forwarding by default on all ports */ ++ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, ++ PCR_MATRIX_CLR); ++ ++ if (dsa_is_cpu_port(ds, i)) ++ mt7530_cpu_port_enable(priv, i); ++ else ++ mt7530_port_disable(ds, i, NULL); ++ } ++ ++ /* Flush the FDB table */ ++ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, 0); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ return mdiobus_read_nested(priv->bus, port, regnum); ++} ++ ++int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ return mdiobus_write_nested(priv->bus, port, regnum, val); ++} ++ ++static void ++mt7530_get_strings(struct dsa_switch *ds, int port, uint8_t *data) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) ++ strncpy(data + i * ETH_GSTRING_LEN, mt7530_mib[i].name, ++ ETH_GSTRING_LEN); ++} ++ ++static void ++mt7530_get_ethtool_stats(struct dsa_switch *ds, int port, ++ uint64_t *data) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ const struct mt7530_mib_desc *mib; ++ u32 reg, i; ++ u64 hi; ++ ++ for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++) { ++ mib = &mt7530_mib[i]; ++ reg = MT7530_PORT_MIB_COUNTER(port) + mib->offset; ++ ++ data[i] = mt7530_read(priv, reg); ++ if (mib->size == 2) { ++ hi = mt7530_read(priv, reg + 4); ++ data[i] |= hi << 32; ++ } ++ } ++} ++ ++static int ++mt7530_get_sset_count(struct dsa_switch *ds) ++{ ++ return ARRAY_SIZE(mt7530_mib); ++} ++ ++static void mt7530_adjust_link(struct dsa_switch *ds, int port, ++ struct phy_device *phydev) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ if (phy_is_pseudo_fixed_link(phydev)) { ++ dev_dbg(priv->dev, "phy-mode for master device = %x\n", ++ phydev->interface); ++ ++ /* Setup TX circuit incluing relevant PAD and driving */ ++ mt7530_pad_clk_setup(ds, phydev->interface); ++ ++ /* Setup RX circuit, relevant PAD and driving on the host ++ * which must be placed after the setup on the device side is ++ * all finished. ++ */ ++ mt7623_pad_clk_setup(ds); ++ } ++} ++ ++static int ++mt7530_cpu_port_enable(struct mt7530_priv *priv, ++ int port) ++{ ++ /* Enable Mediatek header mode on the cpu port */ ++ mt7530_write(priv, MT7530_PVC_P(port), ++ PORT_SPEC_TAG); ++ ++ /* Setup the MAC by default for the cpu port */ ++ mt7530_write(priv, MT7530_PMCR_P(port), PMCR_CPUP_LINK); ++ ++ /* Disable auto learning on the cpu port */ ++ mt7530_set(priv, MT7530_PSC_P(port), SA_DIS); ++ ++ /* Unknown unicast frame fordwarding to the cpu port */ ++ mt7530_set(priv, MT7530_MFC, UNU_FFP(BIT(port))); ++ ++ /* CPU port gets connected to all user ports of ++ * the switch ++ */ ++ mt7530_write(priv, MT7530_PCR_P(port), ++ PCR_MATRIX(priv->ds->enabled_port_mask)); ++ ++ return 0; ++} ++ ++static int ++mt7530_port_enable(struct dsa_switch *ds, int port, ++ struct phy_device *phy) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ /* Setup the MAC for the user port */ ++ mt7530_write(priv, MT7530_PMCR_P(port), PMCR_USERP_LINK); ++ ++ /* Allow the user port gets connected to the cpu port and also ++ * restore the port matrix if the port is the member of a certain ++ * bridge. ++ */ ++ priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT)); ++ priv->ports[port].enable = true; ++ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, ++ priv->ports[port].pm); ++ mt7530_port_set_status(priv, port, 1); ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static void ++mt7530_port_disable(struct dsa_switch *ds, int port, ++ struct phy_device *phy) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ /* Clear up all port matrix which could be restored in the next ++ * enablement for the port. ++ */ ++ priv->ports[port].enable = false; ++ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, ++ PCR_MATRIX_CLR); ++ mt7530_port_set_status(priv, port, 0); ++ ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static void ++mt7530_stp_state_set(struct dsa_switch *ds, int port, u8 state) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u32 stp_state; ++ ++ switch (state) { ++ case BR_STATE_DISABLED: ++ stp_state = MT7530_STP_DISABLED; ++ break; ++ case BR_STATE_BLOCKING: ++ stp_state = MT7530_STP_BLOCKING; ++ break; ++ case BR_STATE_LISTENING: ++ stp_state = MT7530_STP_LISTENING; ++ break; ++ case BR_STATE_LEARNING: ++ stp_state = MT7530_STP_LEARNING; ++ break; ++ case BR_STATE_FORWARDING: ++ default: ++ stp_state = MT7530_STP_FORWARDING; ++ break; ++ } ++ ++ mt7530_rmw(priv, MT7530_SSP_P(port), FID_PST_MASK, stp_state); ++} ++ ++static int ++mt7530_port_bridge_join(struct dsa_switch *ds, int port, ++ struct net_device *bridge) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u32 port_bitmap = BIT(MT7530_CPU_PORT); ++ int i; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ /* Add this port to the port matrix of the other ports in the ++ * same bridge. If the port is disabled, port matrix is kept ++ * and not being setup until the port becomes enabled. ++ */ ++ if (ds->enabled_port_mask & BIT(i) && i != port) { ++ if (ds->ports[i].bridge_dev != bridge) ++ continue; ++ if (priv->ports[i].enable) ++ mt7530_set(priv, MT7530_PCR_P(i), ++ PCR_MATRIX(BIT(port))); ++ priv->ports[i].pm |= PCR_MATRIX(BIT(port)); ++ ++ port_bitmap |= BIT(i); ++ } ++ } ++ ++ /* Add the all other ports to this port matrix. */ ++ if (priv->ports[port].enable) ++ mt7530_rmw(priv, MT7530_PCR_P(port), ++ PCR_MATRIX_MASK, PCR_MATRIX(port_bitmap)); ++ priv->ports[port].pm |= PCR_MATRIX(port_bitmap); ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static void ++mt7530_port_bridge_leave(struct dsa_switch *ds, int port, ++ struct net_device *bridge) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ int i; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ /* Remove this port from the port matrix of the other ports ++ * in the same bridge. If the port is disabled, port matrix ++ * is kept and not being setup until the port becomes enabled. ++ */ ++ if (ds->enabled_port_mask & BIT(i) && i != port) { ++ if (ds->ports[i].bridge_dev != bridge) ++ continue; ++ if (priv->ports[i].enable) ++ mt7530_clear(priv, MT7530_PCR_P(i), ++ PCR_MATRIX(BIT(port))); ++ priv->ports[i].pm &= ~PCR_MATRIX(BIT(port)); ++ } ++ } ++ ++ /* Set the cpu port to be the only one in the port matrix of ++ * this port. ++ */ ++ if (priv->ports[port].enable) ++ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, ++ PCR_MATRIX(BIT(MT7530_CPU_PORT))); ++ priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); ++ ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static int ++mt7530_port_fdb_prepare(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_fdb *fdb, ++ struct switchdev_trans *trans) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ int ret; ++ ++ /* Because auto-learned entrie shares the same FDB table. ++ * an entry is reserved with no port_mask to make sure fdb_add ++ * is called while the entry is still available. ++ */ ++ mutex_lock(&priv->reg_mutex); ++ mt7530_fdb_write(priv, fdb->vid, 0, fdb->addr, -1, STATIC_ENT); ++ ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static void ++mt7530_port_fdb_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_fdb *fdb, ++ struct switchdev_trans *trans) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ u8 port_mask = BIT(port); ++ ++ mutex_lock(&priv->reg_mutex); ++ mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_ENT); ++ mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static int ++mt7530_port_fdb_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_fdb *fdb) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ int ret; ++ u8 port_mask = BIT(port); ++ ++ mutex_lock(&priv->reg_mutex); ++ mt7530_fdb_write(priv, fdb->vid, port_mask, fdb->addr, -1, STATIC_EMP); ++ ret = mt7530_fdb_cmd(priv, MT7530_FDB_WRITE, 0); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int ++mt7530_port_fdb_dump(struct dsa_switch *ds, int port, ++ struct switchdev_obj_port_fdb *fdb, ++ int (*cb)(struct switchdev_obj *obj)) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ struct mt7530_fdb _fdb = { 0 }; ++ int cnt = MT7530_NUM_FDB_RECORDS; ++ int ret = 0; ++ u32 rsp = 0; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ ret = mt7530_fdb_cmd(priv, MT7530_FDB_START, &rsp); ++ if (ret < 0) ++ goto err; ++ ++ do { ++ if (rsp & ATC_SRCH_HIT) { ++ mt7530_fdb_read(priv, &_fdb); ++ if (_fdb.port_mask & BIT(port)) { ++ ether_addr_copy(fdb->addr, _fdb.mac); ++ fdb->vid = _fdb.vid; ++ fdb->ndm_state = _fdb.noarp ? ++ NUD_NOARP : NUD_REACHABLE; ++ ret = cb(&fdb->obj); ++ if (ret < 0) ++ break; ++ } ++ } ++ } while (--cnt && ++ !(rsp & ATC_SRCH_END) && ++ !mt7530_fdb_cmd(priv, MT7530_FDB_NEXT, &rsp)); ++err: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static enum dsa_tag_protocol ++mtk_get_tag_protocol(struct dsa_switch *ds) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ if (!dsa_is_cpu_port(ds, MT7530_CPU_PORT)) { ++ dev_warn(priv->dev, ++ "port not matched with tagging CPU port\n"); ++ return DSA_TAG_PROTO_NONE; ++ } else { ++ return DSA_TAG_PROTO_MTK; ++ } ++} ++ ++static struct dsa_switch_ops mt7530_switch_ops = { ++ .get_tag_protocol = mtk_get_tag_protocol, ++ .setup = mt7530_setup, ++ .get_strings = mt7530_get_strings, ++ .phy_read = mt7530_phy_read, ++ .phy_write = mt7530_phy_write, ++ .get_ethtool_stats = mt7530_get_ethtool_stats, ++ .get_sset_count = mt7530_get_sset_count, ++ .adjust_link = mt7530_adjust_link, ++ .port_enable = mt7530_port_enable, ++ .port_disable = mt7530_port_disable, ++ .port_stp_state_set = mt7530_stp_state_set, ++ .port_bridge_join = mt7530_port_bridge_join, ++ .port_bridge_leave = mt7530_port_bridge_leave, ++ .port_fdb_prepare = mt7530_port_fdb_prepare, ++ .port_fdb_add = mt7530_port_fdb_add, ++ .port_fdb_del = mt7530_port_fdb_del, ++ .port_fdb_dump = mt7530_port_fdb_dump, ++}; ++ ++static int ++mt7530_probe(struct mdio_device *mdiodev) ++{ ++ struct mt7530_priv *priv; ++ struct device_node *dn; ++ ++ dn = mdiodev->dev.of_node; ++ ++ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); ++ if (!priv->ds) ++ return -ENOMEM; ++ ++ /* Use medatek,mcm property to distinguish hardware type that would ++ * casues a little bit differences on power-on sequence. ++ */ ++ priv->mcm = of_property_read_bool(dn, "mediatek,mcm"); ++ if (priv->mcm) { ++ dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n"); ++ ++ priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm"); ++ if (IS_ERR(priv->rstc)) { ++ dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(priv->rstc); ++ } ++ } ++ ++ priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core"); ++ if (IS_ERR(priv->core_pwr)) ++ return PTR_ERR(priv->core_pwr); ++ ++ priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io"); ++ if (IS_ERR(priv->io_pwr)) ++ return PTR_ERR(priv->io_pwr); ++ ++ /* Not MCM that indicates switch works as the remote standalone ++ * integrated circuit so the GPIO pin would be used to complete ++ * the reset, otherwise memory-mapped register accessing used ++ * through syscon provides in the case of MCM. ++ */ ++ if (!priv->mcm) { ++ priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(priv->reset)) { ++ dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(priv->reset); ++ } ++ } ++ ++ priv->bus = mdiodev->bus; ++ priv->dev = &mdiodev->dev; ++ priv->ds->priv = priv; ++ priv->ds->ops = &mt7530_switch_ops; ++ mutex_init(&priv->reg_mutex); ++ lpriv = priv; ++ dev_set_drvdata(&mdiodev->dev, priv); ++ ++ return dsa_register_switch(priv->ds, &mdiodev->dev); ++} ++ ++static void ++mt7530_remove(struct mdio_device *mdiodev) ++{ ++ struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); ++ int ret = 0; ++ ++ ret = regulator_disable(priv->core_pwr); ++ if (ret < 0) ++ dev_err(priv->dev, ++ "Failed to disable core power: %d\n", ret); ++ ++ ret = regulator_disable(priv->io_pwr); ++ if (ret < 0) ++ dev_err(priv->dev, "Failed to disable io pwr: %d\n", ++ ret); ++ ++ dsa_unregister_switch(priv->ds); ++ mutex_destroy(&priv->reg_mutex); ++} ++ ++static const struct of_device_id mt7530_of_match[] = { ++ { .compatible = "mediatek,mt7530" }, ++ { /* sentinel */ }, ++}; ++ ++static struct mdio_driver mt7530_mdio_driver = { ++ .probe = mt7530_probe, ++ .remove = mt7530_remove, ++ .mdiodrv.driver = { ++ .name = "mt7530", ++ .of_match_table = mt7530_of_match, ++ }, ++}; ++ ++mdio_module_driver(mt7530_mdio_driver); ++ ++MODULE_AUTHOR("Sean Wang "); ++MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:mediatek-mt7530"); +diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h +new file mode 100644 +index 0000000..05a612f +--- /dev/null ++++ b/drivers/net/dsa/mt7530.h +@@ -0,0 +1,390 @@ ++/* ++ * Copyright (C) 2017 Sean Wang ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef __MT7530_H ++#define __MT7530_H ++ ++#define MT7530_NUM_PORTS 7 ++#define MT7530_CPU_PORT 6 ++#define MT7530_NUM_FDB_RECORDS 2048 ++ ++#define NUM_TRGMII_CTRL 5 ++ ++#define TRGMII_BASE(x) (0x10000 + (x)) ++ ++/* Registers to ethsys access */ ++#define ETHSYS_CLKCFG0 0x2c ++#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) ++ ++#define SYSC_REG_RSTCTRL 0x34 ++#define RESET_MCM BIT(2) ++ ++/* Registers to mac forward control for unknown frames */ ++#define MT7530_MFC 0x10 ++#define BC_FFP(x) (((x) & 0xff) << 24) ++#define UNM_FFP(x) (((x) & 0xff) << 16) ++#define UNU_FFP(x) (((x) & 0xff) << 8) ++#define UNU_FFP_MASK UNU_FFP(~0) ++ ++/* Registers for address table access */ ++#define MT7530_ATA1 0x74 ++#define STATIC_EMP 0 ++#define STATIC_ENT 3 ++#define MT7530_ATA2 0x78 ++ ++/* Register for address table write data */ ++#define MT7530_ATWD 0x7c ++ ++/* Register for address table control */ ++#define MT7530_ATC 0x80 ++#define ATC_HASH (((x) & 0xfff) << 16) ++#define ATC_BUSY BIT(15) ++#define ATC_SRCH_END BIT(14) ++#define ATC_SRCH_HIT BIT(13) ++#define ATC_INVALID BIT(12) ++#define ATC_MAT(x) (((x) & 0xf) << 8) ++#define ATC_MAT_MACTAB ATC_MAT(0) ++ ++enum mt7530_fdb_cmd { ++ MT7530_FDB_READ = 0, ++ MT7530_FDB_WRITE = 1, ++ MT7530_FDB_FLUSH = 2, ++ MT7530_FDB_START = 4, ++ MT7530_FDB_NEXT = 5, ++}; ++ ++/* Registers for table search read address */ ++#define MT7530_TSRA1 0x84 ++#define MAC_BYTE_0 24 ++#define MAC_BYTE_1 16 ++#define MAC_BYTE_2 8 ++#define MAC_BYTE_3 0 ++#define MAC_BYTE_MASK 0xff ++ ++#define MT7530_TSRA2 0x88 ++#define MAC_BYTE_4 24 ++#define MAC_BYTE_5 16 ++#define CVID 0 ++#define CVID_MASK 0xfff ++ ++#define MT7530_ATRD 0x8C ++#define AGE_TIMER 24 ++#define AGE_TIMER_MASK 0xff ++#define PORT_MAP 4 ++#define PORT_MAP_MASK 0xff ++#define ENT_STATUS 2 ++#define ENT_STATUS_MASK 0x3 ++ ++/* Register for vlan table control */ ++#define MT7530_VTCR 0x90 ++#define VTCR_BUSY BIT(31) ++#define VTCR_FUNC (((x) & 0xf) << 12) ++#define VTCR_FUNC_RD_VID 0x1 ++#define VTCR_FUNC_WR_VID 0x2 ++#define VTCR_FUNC_INV_VID 0x3 ++#define VTCR_FUNC_VAL_VID 0x4 ++#define VTCR_VID ((x) & 0xfff) ++ ++/* Register for setup vlan and acl write data */ ++#define MT7530_VAWD1 0x94 ++#define PORT_STAG BIT(31) ++#define IVL_MAC BIT(30) ++#define PORT_MEM(x) (((x) & 0xff) << 16) ++#define VALID BIT(1) ++ ++#define MT7530_VAWD2 0x98 ++ ++/* Register for port STP state control */ ++#define MT7530_SSP_P(x) (0x2000 + ((x) * 0x100)) ++#define FID_PST(x) ((x) & 0x3) ++#define FID_PST_MASK FID_PST(0x3) ++ ++enum mt7530_stp_state { ++ MT7530_STP_DISABLED = 0, ++ MT7530_STP_BLOCKING = 1, ++ MT7530_STP_LISTENING = 1, ++ MT7530_STP_LEARNING = 2, ++ MT7530_STP_FORWARDING = 3 ++}; ++ ++/* Register for port control */ ++#define MT7530_PCR_P(x) (0x2004 + ((x) * 0x100)) ++#define PORT_VLAN(x) ((x) & 0x3) ++#define PCR_MATRIX(x) (((x) & 0xff) << 16) ++#define PORT_PRI(x) (((x) & 0x7) << 24) ++#define EG_TAG(x) (((x) & 0x3) << 28) ++#define PCR_MATRIX_MASK PCR_MATRIX(0xff) ++#define PCR_MATRIX_CLR PCR_MATRIX(0) ++ ++/* Register for port security control */ ++#define MT7530_PSC_P(x) (0x200c + ((x) * 0x100)) ++#define SA_DIS BIT(4) ++ ++/* Register for port vlan control */ ++#define MT7530_PVC_P(x) (0x2010 + ((x) * 0x100)) ++#define PORT_SPEC_TAG BIT(5) ++#define VLAN_ATTR(x) (((x) & 0x3) << 6) ++#define STAG_VPID (((x) & 0xffff) << 16) ++ ++/* Register for port port-and-protocol based vlan 1 control */ ++#define MT7530_PPBV1_P(x) (0x2014 + ((x) * 0x100)) ++ ++/* Register for port MAC control register */ ++#define MT7530_PMCR_P(x) (0x3000 + ((x) * 0x100)) ++#define PMCR_IFG_XMIT(x) (((x) & 0x3) << 18) ++#define PMCR_MAC_MODE BIT(16) ++#define PMCR_FORCE_MODE BIT(15) ++#define PMCR_TX_EN BIT(14) ++#define PMCR_RX_EN BIT(13) ++#define PMCR_BACKOFF_EN BIT(9) ++#define PMCR_BACKPR_EN BIT(8) ++#define PMCR_TX_FC_EN BIT(5) ++#define PMCR_RX_FC_EN BIT(4) ++#define PMCR_FORCE_SPEED_1000 BIT(3) ++#define PMCR_FORCE_FDX BIT(1) ++#define PMCR_FORCE_LNK BIT(0) ++#define PMCR_COMMON_LINK (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \ ++ PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \ ++ PMCR_TX_EN | PMCR_RX_EN | \ ++ PMCR_TX_FC_EN | PMCR_RX_FC_EN) ++#define PMCR_CPUP_LINK (PMCR_COMMON_LINK | PMCR_FORCE_MODE | \ ++ PMCR_FORCE_SPEED_1000 | \ ++ PMCR_FORCE_FDX | \ ++ PMCR_FORCE_LNK) ++#define PMCR_USERP_LINK PMCR_COMMON_LINK ++#define PMCR_FIXED_LINK (PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \ ++ PMCR_FORCE_MODE | PMCR_TX_EN | \ ++ PMCR_RX_EN | PMCR_BACKPR_EN | \ ++ PMCR_BACKOFF_EN | \ ++ PMCR_FORCE_SPEED_1000 | \ ++ PMCR_FORCE_FDX | \ ++ PMCR_FORCE_LNK) ++#define PMCR_FIXED_LINK_FC (PMCR_FIXED_LINK | \ ++ PMCR_TX_FC_EN | PMCR_RX_FC_EN) ++ ++#define MT7530_PMSR_P(x) (0x3008 + (x) * 0x100) ++ ++/* Register for MIB */ ++#define MT7530_PORT_MIB_COUNTER(x) (0x4000 + (x) * 0x100) ++#define MT7530_MIB_CCR 0x4fe0 ++#define CCR_MIB_ENABLE BIT(31) ++#define CCR_RX_OCT_CNT_GOOD BIT(7) ++#define CCR_RX_OCT_CNT_BAD BIT(6) ++#define CCR_TX_OCT_CNT_GOOD BIT(5) ++#define CCR_TX_OCT_CNT_BAD BIT(4) ++#define CCR_MIB_FLUSH (CCR_RX_OCT_CNT_GOOD | \ ++ CCR_RX_OCT_CNT_BAD | \ ++ CCR_TX_OCT_CNT_GOOD | \ ++ CCR_TX_OCT_CNT_BAD) ++#define CCR_MIB_ACTIVATE (CCR_MIB_ENABLE | \ ++ CCR_RX_OCT_CNT_GOOD | \ ++ CCR_RX_OCT_CNT_BAD | \ ++ CCR_TX_OCT_CNT_GOOD | \ ++ CCR_TX_OCT_CNT_BAD) ++/* Register for system reset */ ++#define MT7530_SYS_CTRL 0x7000 ++#define SYS_CTRL_PHY_RST BIT(2) ++#define SYS_CTRL_SW_RST BIT(1) ++#define SYS_CTRL_REG_RST BIT(0) ++ ++/* Register for hw trap status */ ++#define MT7530_HWTRAP 0x7800 ++ ++/* Register for hw trap modification */ ++#define MT7530_MHWTRAP 0x7804 ++#define MHWTRAP_MANUAL BIT(16) ++#define MHWTRAP_P5_MAC_SEL BIT(13) ++#define MHWTRAP_P6_DIS BIT(8) ++#define MHWTRAP_P5_RGMII_MODE BIT(7) ++#define MHWTRAP_P5_DIS BIT(6) ++#define MHWTRAP_PHY_ACCESS BIT(5) ++ ++/* Register for TOP signal control */ ++#define MT7530_TOP_SIG_CTRL 0x7808 ++#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16)) ++ ++#define MT7530_IO_DRV_CR 0x7810 ++#define P5_IO_CLK_DRV(x) ((x) & 0x3) ++#define P5_IO_DATA_DRV(x) (((x) & 0x3) << 4) ++ ++#define MT7530_P6ECR 0x7830 ++#define P6_INTF_MODE_MASK 0x3 ++#define P6_INTF_MODE(x) ((x) & 0x3) ++ ++/* Registers for TRGMII on the both side */ ++#define MT7530_TRGMII_RCK_CTRL 0x7a00 ++#define GSW_TRGMII_RCK_CTRL 0x300 ++#define RX_RST BIT(31) ++#define RXC_DQSISEL BIT(30) ++#define DQSI1_TAP_MASK (0x7f << 8) ++#define DQSI0_TAP_MASK 0x7f ++#define DQSI1_TAP(x) (((x) & 0x7f) << 8) ++#define DQSI0_TAP(x) ((x) & 0x7f) ++ ++#define MT7530_TRGMII_RCK_RTT 0x7a04 ++#define GSW_TRGMII_RCK_RTT 0x304 ++#define DQS1_GATE BIT(31) ++#define DQS0_GATE BIT(30) ++ ++#define MT7530_TRGMII_RD(x) (0x7a10 + (x) * 8) ++#define GSW_TRGMII_RD(x) (0x310 + (x) * 8) ++#define BSLIP_EN BIT(31) ++#define EDGE_CHK BIT(30) ++#define RD_TAP_MASK 0x7f ++#define RD_TAP(x) ((x) & 0x7f) ++ ++#define GSW_TRGMII_TXCTRL 0x340 ++#define MT7530_TRGMII_TXCTRL 0x7a40 ++#define TRAIN_TXEN BIT(31) ++#define TXC_INV BIT(30) ++#define TX_RST BIT(28) ++ ++#define MT7530_TRGMII_TD_ODT(i) (0x7a54 + 8 * (i)) ++#define GSW_TRGMII_TD_ODT(i) (0x354 + 8 * (i)) ++#define TD_DM_DRVP(x) ((x) & 0xf) ++#define TD_DM_DRVN(x) (((x) & 0xf) << 4) ++ ++#define GSW_INTF_MODE 0x390 ++#define INTF_MODE_TRGMII BIT(1) ++ ++#define MT7530_TRGMII_TCK_CTRL 0x7a78 ++#define TCK_TAP(x) (((x) & 0xf) << 8) ++ ++#define MT7530_P5RGMIIRXCR 0x7b00 ++#define CSR_RGMII_EDGE_ALIGN BIT(8) ++#define CSR_RGMII_RXC_0DEG_CFG(x) ((x) & 0xf) ++ ++#define MT7530_P5RGMIITXCR 0x7b04 ++#define CSR_RGMII_TXC_CFG(x) ((x) & 0x1f) ++ ++#define MT7530_CREV 0x7ffc ++#define CHIP_NAME_SHIFT 16 ++#define MT7530_ID 0x7530 ++ ++/* Registers for core PLL access through mmd indirect */ ++#define CORE_PLL_GROUP2 0x401 ++#define RG_SYSPLL_EN_NORMAL BIT(15) ++#define RG_SYSPLL_VODEN BIT(14) ++#define RG_SYSPLL_LF BIT(13) ++#define RG_SYSPLL_RST_DLY(x) (((x) & 0x3) << 12) ++#define RG_SYSPLL_LVROD_EN BIT(10) ++#define RG_SYSPLL_PREDIV(x) (((x) & 0x3) << 8) ++#define RG_SYSPLL_POSDIV(x) (((x) & 0x3) << 5) ++#define RG_SYSPLL_FBKSEL BIT(4) ++#define RT_SYSPLL_EN_AFE_OLT BIT(0) ++ ++#define CORE_PLL_GROUP4 0x403 ++#define RG_SYSPLL_DDSFBK_EN BIT(12) ++#define RG_SYSPLL_BIAS_EN BIT(11) ++#define RG_SYSPLL_BIAS_LPF_EN BIT(10) ++ ++#define CORE_PLL_GROUP5 0x404 ++#define RG_LCDDS_PCW_NCPO1(x) ((x) & 0xffff) ++ ++#define CORE_PLL_GROUP6 0x405 ++#define RG_LCDDS_PCW_NCPO0(x) ((x) & 0xffff) ++ ++#define CORE_PLL_GROUP7 0x406 ++#define RG_LCDDS_PWDB BIT(15) ++#define RG_LCDDS_ISO_EN BIT(13) ++#define RG_LCCDS_C(x) (((x) & 0x7) << 4) ++#define RG_LCDDS_PCW_NCPO_CHG BIT(3) ++ ++#define CORE_PLL_GROUP10 0x409 ++#define RG_LCDDS_SSC_DELTA(x) ((x) & 0xfff) ++ ++#define CORE_PLL_GROUP11 0x40a ++#define RG_LCDDS_SSC_DELTA1(x) ((x) & 0xfff) ++ ++#define CORE_GSWPLL_GRP1 0x40d ++#define RG_GSWPLL_PREDIV(x) (((x) & 0x3) << 14) ++#define RG_GSWPLL_POSDIV_200M(x) (((x) & 0x3) << 12) ++#define RG_GSWPLL_EN_PRE BIT(11) ++#define RG_GSWPLL_FBKSEL BIT(10) ++#define RG_GSWPLL_BP BIT(9) ++#define RG_GSWPLL_BR BIT(8) ++#define RG_GSWPLL_FBKDIV_200M(x) ((x) & 0xff) ++ ++#define CORE_GSWPLL_GRP2 0x40e ++#define RG_GSWPLL_POSDIV_500M(x) (((x) & 0x3) << 8) ++#define RG_GSWPLL_FBKDIV_500M(x) ((x) & 0xff) ++ ++#define CORE_TRGMII_GSW_CLK_CG 0x410 ++#define REG_GSWCK_EN BIT(0) ++#define REG_TRGMIICK_EN BIT(1) ++ ++#define MIB_DESC(_s, _o, _n) \ ++ { \ ++ .size = (_s), \ ++ .offset = (_o), \ ++ .name = (_n), \ ++ } ++ ++struct mt7530_mib_desc { ++ unsigned int size; ++ unsigned int offset; ++ const char *name; ++}; ++ ++struct mt7530_fdb { ++ u16 vid; ++ u8 port_mask; ++ u8 aging; ++ u8 mac[6]; ++ bool noarp; ++}; ++ ++struct mt7530_port { ++ bool enable; ++ u32 pm; ++}; ++ ++/* struct mt7530_priv - This is the main data structure for holding the state ++ * of the driver ++ * @dev: The device pointer ++ * @ds: The pointer to the dsa core structure ++ * @bus: The bus used for the device and built-in PHY ++ * @rstc: The pointer to reset control used by MCM ++ * @ethernet: The regmap used for access TRGMII-based registers ++ * @core_pwr: The power supplied into the core ++ * @io_pwr: The power supplied into the I/O ++ * @reset: The descriptor for GPIO line tied to its reset pin ++ * @mcm: Flag for distinguishing if standalone IC or module ++ * coupling ++ * @ports: Holding the state among ports ++ * @reg_mutex: The lock for protecting among process accessing ++ * registers ++ */ ++struct mt7530_priv { ++ struct device *dev; ++ struct dsa_switch *ds; ++ struct mii_bus *bus; ++ struct reset_control *rstc; ++ struct regmap *ethernet; ++ struct regulator *core_pwr; ++ struct regulator *io_pwr; ++ struct gpio_desc *reset; ++ bool mcm; ++ ++ struct mt7530_port ports[MT7530_NUM_PORTS]; ++ /* protect among processes for registers access*/ ++ struct mutex reg_mutex; ++}; ++ ++struct mt7530_hw_stats { ++ const char *string; ++ u16 reg; ++ u8 sizeof_stat; ++}; ++ ++#endif /* __MT7530_H */ diff --git a/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch b/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch new file mode 100644 index 0000000000..ca36d4c0d6 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0093-dsa-compat.patch @@ -0,0 +1,98 @@ +Index: linux-4.9.17/drivers/net/dsa/mt7530.c +=================================================================== +--- linux-4.9.17.orig/drivers/net/dsa/mt7530.c ++++ linux-4.9.17/drivers/net/dsa/mt7530.c +@@ -834,6 +834,7 @@ mt7530_port_bridge_join(struct dsa_switc + int i; + + mutex_lock(&priv->reg_mutex); ++ priv->bridge_dev[port] = bridge; + + for (i = 0; i < MT7530_NUM_PORTS; i++) { + /* Add this port to the port matrix of the other ports in the +@@ -841,7 +842,7 @@ mt7530_port_bridge_join(struct dsa_switc + * and not being setup until the port becomes enabled. + */ + if (ds->enabled_port_mask & BIT(i) && i != port) { +- if (ds->ports[i].bridge_dev != bridge) ++ if (priv->bridge_dev[i] != bridge) + continue; + if (priv->ports[i].enable) + mt7530_set(priv, MT7530_PCR_P(i), +@@ -864,8 +865,7 @@ mt7530_port_bridge_join(struct dsa_switc + } + + static void +-mt7530_port_bridge_leave(struct dsa_switch *ds, int port, +- struct net_device *bridge) ++mt7530_port_bridge_leave(struct dsa_switch *ds, int port) + { + struct mt7530_priv *priv = ds->priv; + int i; +@@ -878,7 +878,7 @@ mt7530_port_bridge_leave(struct dsa_swit + * is kept and not being setup until the port becomes enabled. + */ + if (ds->enabled_port_mask & BIT(i) && i != port) { +- if (ds->ports[i].bridge_dev != bridge) ++ if (priv->bridge_dev[i] != priv->bridge_dev[port]) + continue; + if (priv->ports[i].enable) + mt7530_clear(priv, MT7530_PCR_P(i), +@@ -890,6 +890,7 @@ mt7530_port_bridge_leave(struct dsa_swit + /* Set the cpu port to be the only one in the port matrix of + * this port. + */ ++ priv->bridge_dev[port] = NULL; + if (priv->ports[port].enable) + mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, + PCR_MATRIX(BIT(MT7530_CPU_PORT))); +@@ -1033,7 +1034,7 @@ mt7530_probe(struct mdio_device *mdiodev + if (!priv) + return -ENOMEM; + +- priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); ++ priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); + if (!priv->ds) + return -ENOMEM; + +@@ -1076,12 +1077,13 @@ mt7530_probe(struct mdio_device *mdiodev + priv->bus = mdiodev->bus; + priv->dev = &mdiodev->dev; + priv->ds->priv = priv; ++ priv->ds->dev = &mdiodev->dev; + priv->ds->ops = &mt7530_switch_ops; + mutex_init(&priv->reg_mutex); + lpriv = priv; + dev_set_drvdata(&mdiodev->dev, priv); + +- return dsa_register_switch(priv->ds, &mdiodev->dev); ++ return dsa_register_switch(priv->ds, priv->ds->dev->of_node); + } + + static void +Index: linux-4.9.17/drivers/net/dsa/mt7530.h +=================================================================== +--- linux-4.9.17.orig/drivers/net/dsa/mt7530.h ++++ linux-4.9.17/drivers/net/dsa/mt7530.h +@@ -379,6 +379,8 @@ struct mt7530_priv { + struct mt7530_port ports[MT7530_NUM_PORTS]; + /* protect among processes for registers access*/ + struct mutex reg_mutex; ++ ++ struct net_device *bridge_dev[MT7530_NUM_PORTS]; + }; + + struct mt7530_hw_stats { +Index: linux-4.9.17/net/dsa/tag_mtk.c +=================================================================== +--- linux-4.9.17.orig/net/dsa/tag_mtk.c ++++ linux-4.9.17/net/dsa/tag_mtk.c +@@ -35,7 +35,7 @@ static struct sk_buff *mtk_tag_xmit(stru + /* Build the tag after the MAC Source Address */ + mtk_tag = skb->data + 2 * ETH_ALEN; + mtk_tag[0] = 0; +- mtk_tag[1] = (1 << p->dp->index) & MTK_HDR_XMIT_DP_BIT_MASK; ++ mtk_tag[1] = (1 << p->port) & MTK_HDR_XMIT_DP_BIT_MASK; + mtk_tag[2] = 0; + mtk_tag[3] = 0; + diff --git a/target/linux/mediatek/patches-4.9/0094-net-affinity.patch b/target/linux/mediatek/patches-4.9/0094-net-affinity.patch new file mode 100644 index 0000000000..8e51bdd623 --- /dev/null +++ b/target/linux/mediatek/patches-4.9/0094-net-affinity.patch @@ -0,0 +1,40 @@ +Index: linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.c +=================================================================== +--- linux-4.9.17.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2459,15 +2459,23 @@ static int mtk_probe(struct platform_dev + goto err_deinit_hw; + } + ++ for (i = 0; i < 3; i++) { ++ int cpu = i % num_online_cpus(); ++ ++ cpumask_set_cpu(cpu, ð->affinity_mask[i]); ++ } ++ + err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0, + dev_name(eth->dev), eth); + if (err) + goto err_free_dev; ++ irq_set_affinity_hint(eth->irq[1], ð->affinity_mask[1]); + + err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0, + dev_name(eth->dev), eth); + if (err) + goto err_free_dev; ++ irq_set_affinity_hint(eth->irq[2], ð->affinity_mask[2]); + + err = mtk_mdio_init(eth); + if (err) +Index: linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.h +=================================================================== +--- linux-4.9.17.orig/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ linux-4.9.17/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -539,6 +539,7 @@ struct mtk_eth { + struct net_device *netdev[MTK_MAX_DEVS]; + struct mtk_mac *mac[MTK_MAX_DEVS]; + int irq[3]; ++ cpumask_t affinity_mask[3]; + u32 msg_enable; + unsigned long sysclk; + struct regmap *ethsys; diff --git a/target/linux/mediatek/patches-4.9/0101-net-mediatek-add-gsw-mt7530-driver.patch b/target/linux/mediatek/patches-4.9/0101-net-mediatek-add-gsw-mt7530-driver.patch deleted file mode 100644 index d351192e0f..0000000000 --- a/target/linux/mediatek/patches-4.9/0101-net-mediatek-add-gsw-mt7530-driver.patch +++ /dev/null @@ -1,2322 +0,0 @@ -From 6b8a7257e7bcb56782c3f8048311670fe6a80209 Mon Sep 17 00:00:00 2001 -From: John Crispin -Date: Mon, 11 Apr 2016 03:11:54 +0200 -Subject: [PATCH 101/102] net: mediatek add gsw/mt7530 driver - -Signed-off-by: John Crispin ---- - drivers/net/ethernet/mediatek/Makefile | 2 +- - drivers/net/ethernet/mediatek/gsw_mt7620.h | 251 +++++++ - drivers/net/ethernet/mediatek/gsw_mt7623.c | 1084 +++++++++++++++++++++++++++ - drivers/net/ethernet/mediatek/mt7530.c | 808 ++++++++++++++++++++ - drivers/net/ethernet/mediatek/mt7530.h | 20 + - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 59 +- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 + - 7 files changed, 2199 insertions(+), 30 deletions(-) - create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7620.h - create mode 100644 drivers/net/ethernet/mediatek/gsw_mt7623.c - create mode 100644 drivers/net/ethernet/mediatek/mt7530.c - create mode 100644 drivers/net/ethernet/mediatek/mt7530.h - ---- a/drivers/net/ethernet/mediatek/Makefile -+++ b/drivers/net/ethernet/mediatek/Makefile -@@ -2,4 +2,4 @@ - # Makefile for the Mediatek SoCs built-in ethernet macs - # - --obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth_soc.o -+obj-$(CONFIG_NET_MEDIATEK_SOC) += mt7530.o gsw_mt7623.o mtk_eth_soc.o ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/gsw_mt7620.h -@@ -0,0 +1,251 @@ -+/* This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * Copyright (C) 2009-2016 John Crispin -+ * Copyright (C) 2009-2016 Felix Fietkau -+ * Copyright (C) 2013-2016 Michael Lee -+ */ -+ -+#ifndef _RALINK_GSW_MT7620_H__ -+#define _RALINK_GSW_MT7620_H__ -+ -+#define GSW_REG_PHY_TIMEOUT (5 * HZ) -+ -+#define MT7620_GSW_REG_PIAC 0x0004 -+ -+#define GSW_NUM_VLANS 16 -+#define GSW_NUM_VIDS 4096 -+#define GSW_NUM_PORTS 7 -+#define GSW_PORT6 6 -+ -+#define GSW_MDIO_ACCESS BIT(31) -+#define GSW_MDIO_READ BIT(19) -+#define GSW_MDIO_WRITE BIT(18) -+#define GSW_MDIO_START BIT(16) -+#define GSW_MDIO_ADDR_SHIFT 20 -+#define GSW_MDIO_REG_SHIFT 25 -+ -+#define GSW_REG_PORT_PMCR(x) (0x3000 + (x * 0x100)) -+#define GSW_REG_PORT_STATUS(x) (0x3008 + (x * 0x100)) -+#define GSW_REG_SMACCR0 0x3fE4 -+#define GSW_REG_SMACCR1 0x3fE8 -+#define GSW_REG_CKGCR 0x3ff0 -+ -+#define GSW_REG_IMR 0x7008 -+#define GSW_REG_ISR 0x700c -+#define GSW_REG_GPC1 0x7014 -+ -+#define SYSC_REG_CHIP_REV_ID 0x0c -+#define SYSC_REG_CFG 0x10 -+#define SYSC_REG_CFG1 0x14 -+#define RST_CTRL_MCM BIT(2) -+#define SYSC_PAD_RGMII2_MDIO 0x58 -+#define SYSC_GPIO_MODE 0x60 -+ -+#define PORT_IRQ_ST_CHG 0x7f -+ -+#define MT7621_ESW_PHY_POLLING 0x0000 -+#define MT7620_ESW_PHY_POLLING 0x7000 -+ -+#define PMCR_IPG BIT(18) -+#define PMCR_MAC_MODE BIT(16) -+#define PMCR_FORCE BIT(15) -+#define PMCR_TX_EN BIT(14) -+#define PMCR_RX_EN BIT(13) -+#define PMCR_BACKOFF BIT(9) -+#define PMCR_BACKPRES BIT(8) -+#define PMCR_RX_FC BIT(5) -+#define PMCR_TX_FC BIT(4) -+#define PMCR_SPEED(_x) (_x << 2) -+#define PMCR_DUPLEX BIT(1) -+#define PMCR_LINK BIT(0) -+ -+#define PHY_AN_EN BIT(31) -+#define PHY_PRE_EN BIT(30) -+#define PMY_MDC_CONF(_x) ((_x & 0x3f) << 24) -+ -+/* ethernet subsystem config register */ -+#define ETHSYS_SYSCFG0 0x14 -+/* ethernet subsystem clock register */ -+#define ETHSYS_CLKCFG0 0x2c -+#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) -+ -+/* p5 RGMII wrapper TX clock control register */ -+#define MT7530_P5RGMIITXCR 0x7b04 -+/* p5 RGMII wrapper RX clock control register */ -+#define MT7530_P5RGMIIRXCR 0x7b00 -+/* TRGMII TDX ODT registers */ -+#define MT7530_TRGMII_TD0_ODT 0x7a54 -+#define MT7530_TRGMII_TD1_ODT 0x7a5c -+#define MT7530_TRGMII_TD2_ODT 0x7a64 -+#define MT7530_TRGMII_TD3_ODT 0x7a6c -+#define MT7530_TRGMII_TD4_ODT 0x7a74 -+#define MT7530_TRGMII_TD5_ODT 0x7a7c -+/* TRGMII TCK ctrl register */ -+#define MT7530_TRGMII_TCK_CTRL 0x7a78 -+/* TRGMII Tx ctrl register */ -+#define MT7530_TRGMII_TXCTRL 0x7a40 -+/* port 6 extended control register */ -+#define MT7530_P6ECR 0x7830 -+/* IO driver control register */ -+#define MT7530_IO_DRV_CR 0x7810 -+/* top signal control register */ -+#define MT7530_TOP_SIG_CTRL 0x7808 -+/* modified hwtrap register */ -+#define MT7530_MHWTRAP 0x7804 -+/* hwtrap status register */ -+#define MT7530_HWTRAP 0x7800 -+/* status interrupt register */ -+#define MT7530_SYS_INT_STS 0x700c -+/* system nterrupt register */ -+#define MT7530_SYS_INT_EN 0x7008 -+/* system control register */ -+#define MT7530_SYS_CTRL 0x7000 -+/* port MAC status register */ -+#define MT7530_PMSR_P(x) (0x3008 + (x * 0x100)) -+/* port MAC control register */ -+#define MT7530_PMCR_P(x) (0x3000 + (x * 0x100)) -+ -+#define MT7621_XTAL_SHIFT 6 -+#define MT7621_XTAL_MASK 0x7 -+#define MT7621_XTAL_25 6 -+#define MT7621_XTAL_40 3 -+#define MT7621_MDIO_DRV_MASK (3 << 4) -+#define MT7621_GE1_MODE_MASK (3 << 12) -+ -+#define TRGMII_TXCTRL_TXC_INV BIT(30) -+#define P6ECR_INTF_MODE_RGMII BIT(1) -+#define P5RGMIIRXCR_C_ALIGN BIT(8) -+#define P5RGMIIRXCR_DELAY_2 BIT(1) -+#define P5RGMIITXCR_DELAY_2 (BIT(8) | BIT(2)) -+ -+/* TOP_SIG_CTRL bits */ -+#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16)) -+ -+/* MHWTRAP bits */ -+#define MHWTRAP_MANUAL BIT(16) -+#define MHWTRAP_P5_MAC_SEL BIT(13) -+#define MHWTRAP_P6_DIS BIT(8) -+#define MHWTRAP_P5_RGMII_MODE BIT(7) -+#define MHWTRAP_P5_DIS BIT(6) -+#define MHWTRAP_PHY_ACCESS BIT(5) -+ -+/* HWTRAP bits */ -+#define HWTRAP_XTAL_SHIFT 9 -+#define HWTRAP_XTAL_MASK 0x3 -+ -+/* SYS_CTRL bits */ -+#define SYS_CTRL_SW_RST BIT(1) -+#define SYS_CTRL_REG_RST BIT(0) -+ -+/* PMCR bits */ -+#define PMCR_IFG_XMIT_96 BIT(18) -+#define PMCR_MAC_MODE BIT(16) -+#define PMCR_FORCE_MODE BIT(15) -+#define PMCR_TX_EN BIT(14) -+#define PMCR_RX_EN BIT(13) -+#define PMCR_BACK_PRES_EN BIT(9) -+#define PMCR_BACKOFF_EN BIT(8) -+#define PMCR_TX_FC_EN BIT(5) -+#define PMCR_RX_FC_EN BIT(4) -+#define PMCR_FORCE_SPEED_1000 BIT(3) -+#define PMCR_FORCE_FDX BIT(1) -+#define PMCR_FORCE_LNK BIT(0) -+#define PMCR_FIXED_LINK (PMCR_IFG_XMIT_96 | PMCR_MAC_MODE | \ -+ PMCR_FORCE_MODE | PMCR_TX_EN | PMCR_RX_EN | \ -+ PMCR_BACK_PRES_EN | PMCR_BACKOFF_EN | \ -+ PMCR_FORCE_SPEED_1000 | PMCR_FORCE_FDX | \ -+ PMCR_FORCE_LNK) -+ -+#define PMCR_FIXED_LINK_FC (PMCR_FIXED_LINK | \ -+ PMCR_TX_FC_EN | PMCR_RX_FC_EN) -+ -+/* TRGMII control registers */ -+#define GSW_INTF_MODE 0x390 -+#define GSW_TRGMII_TD0_ODT 0x354 -+#define GSW_TRGMII_TD1_ODT 0x35c -+#define GSW_TRGMII_TD2_ODT 0x364 -+#define GSW_TRGMII_TD3_ODT 0x36c -+#define GSW_TRGMII_TXCTL_ODT 0x374 -+#define GSW_TRGMII_TCK_ODT 0x37c -+#define GSW_TRGMII_RCK_CTRL 0x300 -+ -+#define INTF_MODE_TRGMII BIT(1) -+#define TRGMII_RCK_CTRL_RX_RST BIT(31) -+ -+ -+/* possible XTAL speed */ -+#define MT7623_XTAL_40 0 -+#define MT7623_XTAL_20 1 -+#define MT7623_XTAL_25 3 -+ -+/* GPIO port control registers */ -+#define GPIO_OD33_CTRL8 0x4c0 -+#define GPIO_BIAS_CTRL 0xed0 -+#define GPIO_DRV_SEL10 0xf00 -+ -+/* on MT7620 the functio of port 4 can be software configured */ -+enum { -+ PORT4_EPHY = 0, -+ PORT4_EXT, -+}; -+ -+/* struct mt7620_gsw - the structure that holds the SoC specific data -+ * @dev: The Device struct -+ * @base: The base address -+ * @piac_offset: The PIAC base may change depending on SoC -+ * @irq: The IRQ we are using -+ * @port4: The port4 mode on MT7620 -+ * @autopoll: Is MDIO autopolling enabled -+ * @ethsys: The ethsys register map -+ * @pctl: The pin control register map -+ * @clk_trgpll: The trgmii pll clock -+ */ -+struct mt7620_gsw { -+ struct mtk_eth *eth; -+ struct device *dev; -+ void __iomem *base; -+ u32 piac_offset; -+ int irq; -+ int port4; -+ unsigned long int autopoll; -+ -+ struct regmap *ethsys; -+ struct regmap *pctl; -+ -+ struct clk *clk_trgpll; -+ -+ int trgmii_force; -+ bool wllll; -+}; -+ -+/* switch register I/O wrappers */ -+void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg); -+u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg); -+ -+/* the callback used by the driver core to bringup the switch */ -+int mtk_gsw_init(struct mtk_eth *eth); -+ -+/* MDIO access wrappers */ -+int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val); -+int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg); -+void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port); -+int mt7620_has_carrier(struct mtk_eth *eth); -+void mt7620_print_link_state(struct mtk_eth *eth, int port, int link, -+ int speed, int duplex); -+void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val); -+u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg); -+void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg); -+ -+u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, -+ u32 phy_register, u32 write_data); -+u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg); -+void mt7620_handle_carrier(struct mtk_eth *eth); -+ -+#endif ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/gsw_mt7623.c -@@ -0,0 +1,1084 @@ -+/* This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * Copyright (C) 2009-2016 John Crispin -+ * Copyright (C) 2009-2016 Felix Fietkau -+ * Copyright (C) 2013-2016 Michael Lee -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mtk_eth_soc.h" -+#include "gsw_mt7620.h" -+#include "mt7530.h" -+ -+#define ETHSYS_CLKCFG0 0x2c -+#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) -+ -+void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val) -+{ -+ _mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff); -+ _mtk_mdio_write(gsw->eth, 0x1f, (reg >> 2) & 0xf, val & 0xffff); -+ _mtk_mdio_write(gsw->eth, 0x1f, 0x10, val >> 16); -+} -+ -+u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg) -+{ -+ u16 high, low; -+ -+ _mtk_mdio_write(gsw->eth, 0x1f, 0x1f, (reg >> 6) & 0x3ff); -+ low = _mtk_mdio_read(gsw->eth, 0x1f, (reg >> 2) & 0xf); -+ high = _mtk_mdio_read(gsw->eth, 0x1f, 0x10); -+ -+ return (high << 16) | (low & 0xffff); -+} -+ -+void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg) -+{ -+ u32 val = mt7530_mdio_r32(gsw, reg); -+ -+ val &= mask; -+ val |= set; -+ mt7530_mdio_w32(gsw, reg, val); -+} -+ -+void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg) -+{ -+ mtk_w32(gsw->eth, val, reg + 0x10000); -+} -+ -+u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg) -+{ -+ return mtk_r32(gsw->eth, reg + 0x10000); -+} -+ -+void mtk_switch_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, unsigned reg) -+{ -+ u32 val = mtk_switch_r32(gsw, reg); -+ -+ val &= mask; -+ val |= set; -+ -+ mtk_switch_w32(gsw, val, reg); -+} -+ -+int mt7623_gsw_config(struct mtk_eth *eth) -+{ -+ if (eth->mii_bus && mdiobus_get_phy(eth->mii_bus, 0x1f)) -+ mt7530_probe(eth->dev, NULL, eth->mii_bus, 1); -+ -+ return 0; -+} -+ -+static irqreturn_t gsw_interrupt_mt7623(int irq, void *_eth) -+{ -+ struct mtk_eth *eth = (struct mtk_eth *)_eth; -+ struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv; -+ u32 reg, i; -+ -+ reg = mt7530_mdio_r32(gsw, 0x700c); -+ -+ for (i = 0; i < 5; i++) -+ if (reg & BIT(i)) { -+ unsigned int link; -+ -+ link = mt7530_mdio_r32(gsw, -+ 0x3008 + (i * 0x100)) & 0x1; -+ -+ if (link) -+ dev_info(gsw->dev, -+ "port %d link up\n", i); -+ else -+ dev_info(gsw->dev, -+ "port %d link down\n", i); -+ } -+ -+// mt7620_handle_carrier(eth); -+ mt7530_mdio_w32(gsw, 0x700c, 0x1f); -+ -+ return IRQ_HANDLED; -+} -+ -+static void wait_loop(struct mt7620_gsw *gsw) -+{ -+ int i; -+ int read_data; -+ -+ for (i = 0; i < 320; i = i + 1) -+ read_data = mtk_switch_r32(gsw, 0x610); -+} -+ -+static void trgmii_calibration_7623(struct mt7620_gsw *gsw) -+{ -+ -+ unsigned int tap_a[5] = { 0, 0, 0, 0, 0 }; /* minumum delay for all correct */ -+ unsigned int tap_b[5] = { 0, 0, 0, 0, 0 }; /* maximum delay for all correct */ -+ unsigned int final_tap[5]; -+ unsigned int rxc_step_size; -+ unsigned int rxd_step_size; -+ unsigned int read_data; -+ unsigned int tmp; -+ unsigned int rd_wd; -+ int i; -+ unsigned int err_cnt[5]; -+ unsigned int init_toggle_data; -+ unsigned int err_flag[5]; -+ unsigned int err_total_flag; -+ unsigned int training_word; -+ unsigned int rd_tap; -+ u32 val; -+ -+ u32 TRGMII_7623_base; -+ u32 TRGMII_7623_RD_0; -+ u32 TRGMII_RCK_CTRL; -+ -+ TRGMII_7623_base = 0x300; /* 0xFB110300 */ -+ TRGMII_7623_RD_0 = TRGMII_7623_base + 0x10; -+ TRGMII_RCK_CTRL = TRGMII_7623_base; -+ rxd_step_size = 0x1; -+ rxc_step_size = 0x4; -+ init_toggle_data = 0x00000055; -+ training_word = 0x000000AC; -+ -+ /* RX clock gating in MT7623 */ -+ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04); -+ -+ /* Assert RX reset in MT7623 */ -+ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_base + 0x00); -+ -+ /* Set TX OE edge in MT7623 */ -+ mtk_switch_m32(gsw, 0, 0x00002000, TRGMII_7623_base + 0x78); -+ -+ /* Disable RX clock gating in MT7623 */ -+ mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04); -+ -+ /* Release RX reset in MT7623 */ -+ mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base); -+ -+ for (i = 0; i < 5; i++) -+ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8); -+ -+ pr_err("Enable Training Mode in MT7530\n"); -+ read_data = mt7530_mdio_r32(gsw, 0x7A40); -+ read_data |= 0xC0000000; -+ mt7530_mdio_w32(gsw, 0x7A40, read_data); /* Enable Training Mode in MT7530 */ -+ err_total_flag = 0; -+ pr_err("Adjust RXC delay in MT7623\n"); -+ read_data = 0x0; -+ while (err_total_flag == 0 && read_data != 0x68) { -+ pr_err("2nd Enable EDGE CHK in MT7623\n"); -+ /* Enable EDGE CHK in MT7623 */ -+ for (i = 0; i < 5; i++) -+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); -+ -+ wait_loop(gsw); -+ err_total_flag = 1; -+ for (i = 0; i < 5; i++) { -+ err_cnt[i] = -+ mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 8; -+ err_cnt[i] &= 0x0000000f; -+ rd_wd = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) >> 16; -+ rd_wd &= 0x000000ff; -+ val = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); -+ pr_err("ERR_CNT = %d, RD_WD =%x, TRGMII_7623_RD_0=%x\n", -+ err_cnt[i], rd_wd, val); -+ if (err_cnt[i] != 0) { -+ err_flag[i] = 1; -+ } else if (rd_wd != 0x55) { -+ err_flag[i] = 1; -+ } else { -+ err_flag[i] = 0; -+ } -+ err_total_flag = err_flag[i] & err_total_flag; -+ } -+ -+ pr_err("2nd Disable EDGE CHK in MT7623\n"); -+ /* Disable EDGE CHK in MT7623 */ -+ for (i = 0; i < 5; i++) -+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); -+ wait_loop(gsw); -+ pr_err("2nd Disable EDGE CHK in MT7623\n"); -+ /* Adjust RXC delay */ -+ /* RX clock gating in MT7623 */ -+ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x04); -+ read_data = mtk_switch_r32(gsw, TRGMII_7623_base); -+ if (err_total_flag == 0) { -+ tmp = (read_data & 0x0000007f) + rxc_step_size; -+ pr_err(" RXC delay = %d\n", tmp); -+ read_data >>= 8; -+ read_data &= 0xffffff80; -+ read_data |= tmp; -+ read_data <<= 8; -+ read_data &= 0xffffff80; -+ read_data |= tmp; -+ mtk_switch_w32(gsw, read_data, TRGMII_7623_base); -+ } else { -+ tmp = (read_data & 0x0000007f) + 16; -+ pr_err(" RXC delay = %d\n", tmp); -+ read_data >>= 8; -+ read_data &= 0xffffff80; -+ read_data |= tmp; -+ read_data <<= 8; -+ read_data &= 0xffffff80; -+ read_data |= tmp; -+ mtk_switch_w32(gsw, read_data, TRGMII_7623_base); -+ } -+ read_data &= 0x000000ff; -+ -+ /* Disable RX clock gating in MT7623 */ -+ mtk_switch_m32(gsw, 0, 0xC0000000, TRGMII_7623_base + 0x04); -+ for (i = 0; i < 5; i++) -+ mtk_switch_m32(gsw, 0, 0x80000000, TRGMII_7623_RD_0 + i * 8); -+ } -+ -+ /* Read RD_WD MT7623 */ -+ for (i = 0; i < 5; i++) { -+ rd_tap = 0; -+ while (err_flag[i] != 0 && rd_tap != 128) { -+ /* Enable EDGE CHK in MT7623 */ -+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); -+ wait_loop(gsw); -+ -+ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); -+ err_cnt[i] = (read_data >> 8) & 0x0000000f; /* Read MT7623 Errcnt */ -+ rd_wd = (read_data >> 16) & 0x000000ff; -+ if (err_cnt[i] != 0 || rd_wd != 0x55) { -+ err_flag[i] = 1; -+ } else { -+ err_flag[i] = 0; -+ } -+ /* Disable EDGE CHK in MT7623 */ -+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); -+ wait_loop(gsw); -+ if (err_flag[i] != 0) { -+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7623 */ -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mtk_switch_w32(gsw, read_data, -+ TRGMII_7623_RD_0 + i * 8); -+ tap_a[i] = rd_tap; -+ } else { -+ rd_tap = (read_data & 0x0000007f) + 48; -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mtk_switch_w32(gsw, read_data, -+ TRGMII_7623_RD_0 + i * 8); -+ } -+ -+ } -+ pr_err("MT7623 %dth bit Tap_a = %d\n", i, tap_a[i]); -+ } -+ /* pr_err("Last While Loop\n"); */ -+ for (i = 0; i < 5; i++) { -+ while ((err_flag[i] == 0) && (rd_tap != 128)) { -+ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); -+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7623 */ -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8); -+ /* Enable EDGE CHK in MT7623 */ -+ val = -+ mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8) | 0x40000000; -+ val &= 0x4fffffff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_RD_0 + i * 8); -+ wait_loop(gsw); -+ read_data = mtk_switch_r32(gsw, TRGMII_7623_RD_0 + i * 8); -+ err_cnt[i] = (read_data >> 8) & 0x0000000f; /* Read MT7623 Errcnt */ -+ rd_wd = (read_data >> 16) & 0x000000ff; -+ if (err_cnt[i] != 0 || rd_wd != 0x55) { -+ err_flag[i] = 1; -+ } else { -+ err_flag[i] = 0; -+ } -+ -+ /* Disable EDGE CHK in MT7623 */ -+ mtk_switch_m32(gsw, 0x4fffffff, 0x40000000, TRGMII_7623_RD_0 + i * 8); -+ wait_loop(gsw); -+ -+ } -+ -+ tap_b[i] = rd_tap; /* -rxd_step_size; */ -+ pr_err("MT7623 %dth bit Tap_b = %d\n", i, tap_b[i]); -+ final_tap[i] = (tap_a[i] + tap_b[i]) / 2; /* Calculate RXD delay = (TAP_A + TAP_B)/2 */ -+ read_data = (read_data & 0xffffff80) | final_tap[i]; -+ mtk_switch_w32(gsw, read_data, TRGMII_7623_RD_0 + i * 8); -+ } -+ -+ read_data = mt7530_mdio_r32(gsw, 0x7A40); -+ read_data &= 0x3fffffff; -+ mt7530_mdio_w32(gsw, 0x7A40, read_data); -+} -+ -+static void trgmii_calibration_7530(struct mt7620_gsw *gsw) -+{ -+ -+ unsigned int tap_a[5] = { 0, 0, 0, 0, 0 }; -+ unsigned int tap_b[5] = { 0, 0, 0, 0, 0 }; -+ unsigned int final_tap[5]; -+ unsigned int rxc_step_size; -+ unsigned int rxd_step_size; -+ unsigned int read_data; -+ unsigned int tmp = 0; -+ int i; -+ unsigned int err_cnt[5]; -+ unsigned int rd_wd; -+ unsigned int init_toggle_data; -+ unsigned int err_flag[5]; -+ unsigned int err_total_flag; -+ unsigned int training_word; -+ unsigned int rd_tap; -+ -+ u32 TRGMII_7623_base; -+ u32 TRGMII_7530_RD_0; -+ u32 TRGMII_RCK_CTRL; -+ u32 TRGMII_7530_base; -+ u32 TRGMII_7530_TX_base; -+ u32 val; -+ -+ TRGMII_7623_base = 0x300; -+ TRGMII_7530_base = 0x7A00; -+ TRGMII_7530_RD_0 = TRGMII_7530_base + 0x10; -+ TRGMII_RCK_CTRL = TRGMII_7623_base; -+ rxd_step_size = 0x1; -+ rxc_step_size = 0x8; -+ init_toggle_data = 0x00000055; -+ training_word = 0x000000AC; -+ -+ TRGMII_7530_TX_base = TRGMII_7530_base + 0x50; -+ -+ /* pr_err("Calibration begin ........\n"); */ -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); -+ read_data = mt7530_mdio_r32(gsw, 0x7a10); -+ /* pr_err("TRGMII_7530_RD_0 is %x\n", read_data); */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); -+ read_data &= 0x3fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* RX clock gating in MT7530 */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x78); -+ read_data |= 0x00002000; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x78, read_data); /* Set TX OE edge in MT7530 */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ read_data |= 0x80000000; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Assert RX reset in MT7530 */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ read_data &= 0x7fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Release RX reset in MT7530 */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); -+ read_data |= 0xC0000000; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* Disable RX clock gating in MT7530 */ -+ -+ /* pr_err("Enable Training Mode in MT7623\n"); */ -+ /*Enable Training Mode in MT7623 */ -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); -+ if (gsw->trgmii_force == 2000) { -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0xC0000000; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); -+ } else { -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x40) | 0x80000000; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x40); -+ } -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x078) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x078); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x50) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x50); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x58) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x58); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x60) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x60); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x68) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x68); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x70) & 0xfffff0ff; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x70); -+ val = mtk_switch_r32(gsw, TRGMII_7623_base + 0x78) & 0x00000800; -+ mtk_switch_w32(gsw, val, TRGMII_7623_base + 0x78); -+ err_total_flag = 0; -+ /* pr_err("Adjust RXC delay in MT7530\n"); */ -+ read_data = 0x0; -+ while (err_total_flag == 0 && (read_data != 0x68)) { -+ /* pr_err("2nd Enable EDGE CHK in MT7530\n"); */ -+ /* Enable EDGE CHK in MT7530 */ -+ for (i = 0; i < 5; i++) { -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ /* pr_err("2nd Disable EDGE CHK in MT7530\n"); */ -+ err_cnt[i] = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ /* pr_err("***** MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */ -+ /* pr_err("MT7530 %dth bit ERR_CNT =%x\n",i, err_cnt[i]); */ -+ err_cnt[i] >>= 8; -+ err_cnt[i] &= 0x0000ff0f; -+ rd_wd = err_cnt[i] >> 8; -+ rd_wd &= 0x000000ff; -+ err_cnt[i] &= 0x0000000f; -+ /* read_data = mt7530_mdio_r32(gsw,0x7a10,&read_data); */ -+ if (err_cnt[i] != 0) { -+ err_flag[i] = 1; -+ } else if (rd_wd != 0x55) { -+ err_flag[i] = 1; -+ } else { -+ err_flag[i] = 0; -+ } -+ if (i == 0) { -+ err_total_flag = err_flag[i]; -+ } else { -+ err_total_flag = err_flag[i] & err_total_flag; -+ } -+ /* Disable EDGE CHK in MT7530 */ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ } -+ /*Adjust RXC delay */ -+ if (err_total_flag == 0) { -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ read_data |= 0x80000000; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Assert RX reset in MT7530 */ -+ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); -+ read_data &= 0x3fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* RX clock gating in MT7530 */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ tmp = read_data; -+ tmp &= 0x0000007f; -+ tmp += rxc_step_size; -+ /* pr_err("Current rxc delay = %d\n", tmp); */ -+ read_data &= 0xffffff80; -+ read_data |= tmp; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ /* pr_err("Current RXC delay = %x\n", read_data); */ -+ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_base); -+ read_data &= 0x7fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base, read_data); /* Release RX reset in MT7530 */ -+ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_base + 0x04); -+ read_data |= 0xc0000000; -+ mt7530_mdio_w32(gsw, TRGMII_7530_base + 0x04, read_data); /* Disable RX clock gating in MT7530 */ -+ pr_err("####### MT7530 RXC delay is %d\n", tmp); -+ } -+ read_data = tmp; -+ } -+ pr_err("Finish RXC Adjustment while loop\n"); -+ -+ /* pr_err("Read RD_WD MT7530\n"); */ -+ /* Read RD_WD MT7530 */ -+ for (i = 0; i < 5; i++) { -+ rd_tap = 0; -+ while (err_flag[i] != 0 && rd_tap != 128) { -+ /* Enable EDGE CHK in MT7530 */ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ err_cnt[i] = (read_data >> 8) & 0x0000000f; -+ rd_wd = (read_data >> 16) & 0x000000ff; -+ if (err_cnt[i] != 0 || rd_wd != 0x55) { -+ err_flag[i] = 1; -+ } else { -+ err_flag[i] = 0; -+ } -+ if (err_flag[i] != 0) { -+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; /* Add RXD delay in MT7530 */ -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ tap_a[i] = rd_tap; -+ } else { -+ tap_a[i] = (read_data & 0x0000007f); /* Record the min delay TAP_A */ -+ rd_tap = tap_a[i] + 0x4; -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ } -+ -+ /* Disable EDGE CHK in MT7530 */ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ -+ } -+ pr_err("MT7530 %dth bit Tap_a = %d\n", i, tap_a[i]); -+ } -+ -+ /* pr_err("Last While Loop\n"); */ -+ for (i = 0; i < 5; i++) { -+ rd_tap = 0; -+ while (err_flag[i] == 0 && (rd_tap != 128)) { -+ /* Enable EDGE CHK in MT7530 */ -+ read_data = mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ err_cnt[i] = (read_data >> 8) & 0x0000000f; -+ rd_wd = (read_data >> 16) & 0x000000ff; -+ if (err_cnt[i] != 0 || rd_wd != 0x55) -+ err_flag[i] = 1; -+ else -+ err_flag[i] = 0; -+ -+ if (err_flag[i] == 0 && (rd_tap != 128)) { -+ /* Add RXD delay in MT7530 */ -+ rd_tap = (read_data & 0x0000007f) + rxd_step_size; -+ read_data = (read_data & 0xffffff80) | rd_tap; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ } -+ /* Disable EDGE CHK in MT7530 */ -+ read_data = -+ mt7530_mdio_r32(gsw, TRGMII_7530_RD_0 + i * 8); -+ read_data |= 0x40000000; -+ read_data &= 0x4fffffff; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, -+ read_data); -+ wait_loop(gsw); -+ } -+ tap_b[i] = rd_tap; /* - rxd_step_size; */ -+ pr_err("MT7530 %dth bit Tap_b = %d\n", i, tap_b[i]); -+ /* Calculate RXD delay = (TAP_A + TAP_B)/2 */ -+ final_tap[i] = (tap_a[i] + tap_b[i]) / 2; -+ /* pr_err("########****** MT7530 %dth bit Final Tap = %d\n", i, final_tap[i]); */ -+ -+ read_data = (read_data & 0xffffff80) | final_tap[i]; -+ mt7530_mdio_w32(gsw, TRGMII_7530_RD_0 + i * 8, read_data); -+ } -+ -+ if (gsw->trgmii_force == 2000) -+ mtk_switch_m32(gsw, 0x7fffffff, 0, TRGMII_7623_base + 0x40); -+ else -+ mtk_switch_m32(gsw, 0x3fffffff, 0, TRGMII_7623_base + 0x40); -+ -+} -+ -+static void mt7530_trgmii_clock_setting(struct mt7620_gsw *gsw, u32 xtal_mode) -+{ -+ -+ u32 regValue; -+ -+ /* TRGMII Clock */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x404); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ -+ if (xtal_mode == 1) { -+ /* 25MHz */ -+ if (gsw->trgmii_force == 2600) -+ /* 325MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1a00); -+ else if (gsw->trgmii_force == 2000) -+ /* 250MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1400); -+ } else if (xtal_mode == 2) { -+ /* 40MHz */ -+ if (gsw->trgmii_force == 2600) -+ /* 325MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1040); -+ else if (gsw->trgmii_force == 2000) -+ /* 250MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0c80); -+ } -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x405); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x409); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ if (xtal_mode == 1) -+ /* 25MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0057); -+ else -+ /* 40MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0087); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40a); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ if (xtal_mode == 1) -+ /* 25MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0057); -+ else -+ /* 40MHz */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0087); -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x403); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1800); -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x403); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1c00); -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x401); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0xc020); -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x406); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0xa030); -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x406); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0xa038); -+ -+// udelay(120); /* for MT7623 bring up test */ -+ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x3); -+ -+ regValue = mt7530_mdio_r32(gsw, 0x7830); -+ regValue &= 0xFFFFFFFC; -+ regValue |= 0x00000001; -+ mt7530_mdio_w32(gsw, 0x7830, regValue); -+ -+ regValue = mt7530_mdio_r32(gsw, 0x7a40); -+ regValue &= ~(0x1 << 30); -+ regValue &= ~(0x1 << 28); -+ mt7530_mdio_w32(gsw, 0x7a40, regValue); -+ -+ mt7530_mdio_w32(gsw, 0x7a78, 0x55); -+// udelay(100); /* for mt7623 bring up test */ -+ -+ mtk_switch_m32(gsw, 0x7fffffff, 0, 0x300); -+ -+ trgmii_calibration_7623(gsw); -+ trgmii_calibration_7530(gsw); -+ -+ mtk_switch_m32(gsw, 0, 0x80000000, 0x300); -+ mtk_switch_m32(gsw, 0, 0x7fffffff, 0x300); -+ -+ /*MT7530 RXC reset */ -+ regValue = mt7530_mdio_r32(gsw, 0x7a00); -+ regValue |= (0x1 << 31); -+ mt7530_mdio_w32(gsw, 0x7a00, regValue); -+ mdelay(1); -+ regValue &= ~(0x1 << 31); -+ mt7530_mdio_w32(gsw, 0x7a00, regValue); -+ mdelay(100); -+} -+ -+static void mt7623_hw_init(struct mtk_eth *eth, struct mt7620_gsw *gsw, struct device_node *np) -+{ -+ u32 i; -+ u32 val; -+ u32 xtal_mode; -+ -+ regmap_update_bits(gsw->ethsys, ETHSYS_CLKCFG0, -+ ETHSYS_TRGMII_CLK_SEL362_5, -+ ETHSYS_TRGMII_CLK_SEL362_5); -+ -+ /* reset the TRGMII core */ -+ mtk_switch_m32(gsw, 0, INTF_MODE_TRGMII, GSW_INTF_MODE); -+ /* Assert MT7623 RXC reset */ -+ mtk_switch_m32(gsw, 0, TRGMII_RCK_CTRL_RX_RST, GSW_TRGMII_RCK_CTRL); -+ -+ /* Hardware reset Switch */ -+ device_reset(eth->dev); -+ -+ /* Wait for Switch Reset Completed*/ -+ for (i = 0; i < 100; i++) { -+ mdelay(10); -+ if (mt7530_mdio_r32(gsw, MT7530_HWTRAP)) -+ break; -+ } -+ -+ /* turn off all PHYs */ -+ for (i = 0; i <= 4; i++) { -+ val = _mtk_mdio_read(gsw->eth, i, 0x0); -+ val |= BIT(11); -+ _mtk_mdio_write(gsw->eth, i, 0x0, val); -+ } -+ -+ /* reset the switch */ -+ mt7530_mdio_w32(gsw, MT7530_SYS_CTRL, -+ SYS_CTRL_SW_RST | SYS_CTRL_REG_RST); -+ udelay(100); -+ -+ /* GE1, Force 1000M/FD, FC ON */ -+ mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK_FC); -+ -+ /* GE2, Force 1000M/FD, FC ON */ -+ mt7530_mdio_w32(gsw, MT7530_PMCR_P(5), PMCR_FIXED_LINK_FC); -+ -+ /* Enable Port 6, P5 as GMAC5, P5 disable */ -+ val = mt7530_mdio_r32(gsw, MT7530_MHWTRAP); -+ if (gsw->eth->mac[0] && -+ of_phy_is_fixed_link(gsw->eth->mac[0]->of_node)) -+ /* Enable Port 6 */ -+ val &= ~MHWTRAP_P6_DIS; -+ else -+ /* Disable Port 6 */ -+ val |= MHWTRAP_P6_DIS; -+ if (gsw->eth->mac[1] && -+ of_phy_is_fixed_link(gsw->eth->mac[1]->of_node)) { -+ /* Enable Port 5 */ -+ val &= ~MHWTRAP_P5_DIS; -+ /* Port 5 as PHY */ -+ val &= ~MHWTRAP_P5_MAC_SEL; -+ } else { -+ /* Disable Port 5 */ -+ val |= MHWTRAP_P5_DIS; -+ /* Port 5 as GMAC */ -+ val |= MHWTRAP_P5_MAC_SEL; -+ val |= BIT(7); -+ mt7530_mdio_w32(gsw, MT7530_PMCR_P(5), 0x8000); -+ } -+ /* gphy to port 0/4 */ -+ if (gsw->wllll) -+ val |= BIT(20); -+ else -+ val &= ~BIT(20); -+ -+ /* Set MT7530 phy direct access mode**/ -+ val &= ~MHWTRAP_PHY_ACCESS; -+ /* manual override of HW-Trap */ -+ val |= MHWTRAP_MANUAL; -+ mt7530_mdio_w32(gsw, MT7530_MHWTRAP, val); -+ dev_info(gsw->dev, "Setting MHWTRAP to 0x%08x\n", val); -+ -+ val = mt7530_mdio_r32(gsw, 0x7800); -+ val = (val >> 9) & 0x3; -+ if (val == 0x3) { -+ xtal_mode = 1; -+ /* 25Mhz Xtal - do nothing */ -+ } else if (val == 0x2) { -+ /* 40Mhz */ -+ xtal_mode = 2; -+ -+ /* disable MT7530 core clock */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x0); -+ -+ /* disable MT7530 PLL */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40d); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x2020); -+ -+ /* for MT7530 core clock = 500Mhz */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40e); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x119); -+ -+ /* enable MT7530 PLL */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x40d); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x2820); -+ -+ udelay(20); -+ -+ /* enable MT7530 core clock */ -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x1f); -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x410); -+ _mtk_mdio_write(gsw->eth, 0, 13, 0x401f); -+ } else { -+ xtal_mode = 3; -+ /* 20Mhz Xtal - TODO */ -+ } -+ -+ /* RGMII */ -+ _mtk_mdio_write(gsw->eth, 0, 14, 0x1); -+ -+ /* set MT7530 central align */ -+ val = mt7530_mdio_r32(gsw, 0x7830); -+ val &= ~1; -+ val |= 1<<1; -+ mt7530_mdio_w32(gsw, 0x7830, val); -+ -+ val = mt7530_mdio_r32(gsw, 0x7a40); -+ val &= ~(1<<30); -+ mt7530_mdio_w32(gsw, 0x7a40, val); -+ -+ mt7530_mdio_w32(gsw, 0x7a78, 0x855); -+ -+ /* delay setting for 10/1000M */ -+ mt7530_mdio_w32(gsw, 0x7b00, 0x104); -+ mt7530_mdio_w32(gsw, 0x7b04, 0x10); -+ -+ /* lower Tx Driving */ -+ mt7530_mdio_w32(gsw, 0x7a54, 0x88); -+ mt7530_mdio_w32(gsw, 0x7a5c, 0x88); -+ mt7530_mdio_w32(gsw, 0x7a64, 0x88); -+ mt7530_mdio_w32(gsw, 0x7a6c, 0x88); -+ mt7530_mdio_w32(gsw, 0x7a74, 0x88); -+ mt7530_mdio_w32(gsw, 0x7a7c, 0x88); -+ mt7530_mdio_w32(gsw, 0x7810, 0x11); -+ -+ /* Set MT7623/MT7683 TX Driving */ -+ mtk_switch_w32(gsw, 0x88, 0x354); -+ mtk_switch_w32(gsw, 0x88, 0x35c); -+ mtk_switch_w32(gsw, 0x88, 0x364); -+ mtk_switch_w32(gsw, 0x88, 0x36c); -+ mtk_switch_w32(gsw, 0x88, 0x374); -+ mtk_switch_w32(gsw, 0x88, 0x37c); -+ -+ /* Set GE2 driving and slew rate */ -+ regmap_write(gsw->pctl, 0xF00, 0xe00); -+ /* set GE2 TDSEL */ -+ regmap_write(gsw->pctl, 0x4C0, 0x5); -+ /* set GE2 TUNE */ -+ regmap_write(gsw->pctl, 0xED0, 0x0); -+ -+ regmap_write(gsw->pctl, 0xb70, 0); -+ regmap_write(gsw->pctl, 0x250, 0xffff); -+ regmap_write(gsw->pctl, 0x260, 0xff); -+ regmap_write(gsw->pctl, 0x380, 0x37); -+ regmap_write(gsw->pctl, 0x390, 0x40); -+ -+ mt7530_trgmii_clock_setting(gsw, xtal_mode); -+ -+ //LANWANPartition(gsw); -+ -+ /* disable EEE */ -+ for (i = 0; i <= 4; i++) { -+ _mtk_mdio_write(gsw->eth, i, 13, 0x7); -+ _mtk_mdio_write(gsw->eth, i, 14, 0x3C); -+ _mtk_mdio_write(gsw->eth, i, 13, 0x4007); -+ _mtk_mdio_write(gsw->eth, i, 14, 0x0); -+ -+ /* Increase SlvDPSready time */ -+ _mtk_mdio_write(gsw->eth, i, 31, 0x52b5); -+ _mtk_mdio_write(gsw->eth, i, 16, 0xafae); -+ _mtk_mdio_write(gsw->eth, i, 18, 0x2f); -+ _mtk_mdio_write(gsw->eth, i, 16, 0x8fae); -+ -+ /* Incease post_update_timer */ -+ _mtk_mdio_write(gsw->eth, i, 31, 0x3); -+ _mtk_mdio_write(gsw->eth, i, 17, 0x4b); -+ -+ /* Adjust 100_mse_threshold */ -+ _mtk_mdio_write(gsw->eth, i, 13, 0x1e); -+ _mtk_mdio_write(gsw->eth, i, 14, 0x123); -+ _mtk_mdio_write(gsw->eth, i, 13, 0x401e); -+ _mtk_mdio_write(gsw->eth, i, 14, 0xffff); -+ -+ /* Disable mcc */ -+ _mtk_mdio_write(gsw->eth, i, 13, 0x1e); -+ _mtk_mdio_write(gsw->eth, i, 14, 0xa6); -+ _mtk_mdio_write(gsw->eth, i, 13, 0x401e); -+ _mtk_mdio_write(gsw->eth, i, 14, 0x300); -+ -+ /* Disable HW auto downshift*/ -+ _mtk_mdio_write(gsw->eth, i, 31, 0x1); -+ val = _mtk_mdio_read(gsw->eth, i, 0x14); -+ val &= ~(1<<4); -+ _mtk_mdio_write(gsw->eth, i, 0x14, val); -+ } -+ -+ /* turn on all PHYs */ -+ for (i = 0; i <= 4; i++) { -+ val = _mtk_mdio_read(gsw->eth, i, 0); -+ val &= ~BIT(11); -+ _mtk_mdio_write(gsw->eth, i, 0, val); -+ } -+ -+ /* enable irq */ -+ mt7530_mdio_m32(gsw, 0, TOP_SIG_CTRL_NORMAL, MT7530_TOP_SIG_CTRL); -+} -+ -+static const struct of_device_id mediatek_gsw_match[] = { -+ { .compatible = "mediatek,mt7623-gsw" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, mediatek_gsw_match); -+ -+int mtk_gsw_init(struct mtk_eth *eth) -+{ -+ struct device_node *np = eth->switch_np; -+ struct platform_device *pdev = of_find_device_by_node(np); -+ struct mt7620_gsw *gsw; -+ -+ if (!pdev) -+ return -ENODEV; -+ -+ if (!of_device_is_compatible(np, mediatek_gsw_match->compatible)) -+ return -EINVAL; -+ -+ gsw = platform_get_drvdata(pdev); -+ if (!gsw) -+ return -ENODEV; -+ gsw->eth = eth; -+ eth->sw_priv = gsw; -+ -+ mt7623_hw_init(eth, gsw, np); -+ -+ if (request_threaded_irq(gsw->irq, gsw_interrupt_mt7623, NULL, 0, -+ "gsw", eth)) -+ pr_err("fail to request irq\n"); -+ mt7530_mdio_w32(gsw, 0x7008, 0x1f); -+ -+ return 0; -+} -+ -+static int mt7623_gsw_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct device_node *pctl; -+ int reset_pin, ret; -+ struct mt7620_gsw *gsw; -+ struct regulator *supply; -+ -+ gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL); -+ if (!gsw) -+ return -ENOMEM; -+ -+ gsw->dev = &pdev->dev; -+ gsw->trgmii_force = 2000; -+ gsw->irq = irq_of_parse_and_map(np, 0); -+ if (gsw->irq < 0) -+ return -EINVAL; -+ -+ gsw->ethsys = syscon_regmap_lookup_by_phandle(np, "mediatek,ethsys"); -+ if (IS_ERR(gsw->ethsys)) -+ return PTR_ERR(gsw->ethsys); -+ -+ reset_pin = of_get_named_gpio(np, "mediatek,reset-pin", 0); -+ if (reset_pin < 0) -+ return reset_pin; -+ -+ pctl = of_parse_phandle(np, "mediatek,pctl-regmap", 0); -+ if (IS_ERR(pctl)) -+ return PTR_ERR(pctl); -+ -+ gsw->pctl = syscon_node_to_regmap(pctl); -+ if (IS_ERR(pctl)) -+ return PTR_ERR(pctl); -+ -+ ret = devm_gpio_request(&pdev->dev, reset_pin, "mt7530-reset"); -+ if (ret) -+ return ret; -+ -+ gsw->clk_trgpll = devm_clk_get(&pdev->dev, "trgpll"); -+ -+ if (IS_ERR(gsw->clk_trgpll)) -+ return -ENODEV; -+ -+ supply = devm_regulator_get(&pdev->dev, "mt7530"); -+ if (IS_ERR(supply)) -+ return PTR_ERR(supply); -+ -+ regulator_set_voltage(supply, 1000000, 1000000); -+ ret = regulator_enable(supply); -+ if (ret) { -+ dev_err(&pdev->dev, "Failed to enable reg-7530: %d\n", ret); -+ return ret; -+ } -+ -+ gsw->wllll = of_property_read_bool(np, "mediatek,wllll"); -+ -+ pm_runtime_enable(&pdev->dev); -+ pm_runtime_get_sync(&pdev->dev); -+ -+ ret = clk_set_rate(gsw->clk_trgpll, 500000000); -+ if (ret) -+ return ret; -+ -+ regmap_write(gsw->ethsys, 0x34, 0x800000); -+ regmap_write(gsw->ethsys, 0x34, 0x0); -+ -+ clk_prepare_enable(gsw->clk_trgpll); -+ -+ gpio_direction_output(reset_pin, 0); -+ udelay(1000); -+ gpio_set_value(reset_pin, 1); -+ mdelay(100); -+ -+ platform_set_drvdata(pdev, gsw); -+ -+ return 0; -+} -+ -+static int mt7623_gsw_remove(struct platform_device *pdev) -+{ -+ struct mt7620_gsw *gsw = platform_get_drvdata(pdev); -+ -+ clk_disable_unprepare(gsw->clk_trgpll); -+ -+ pm_runtime_put_sync(&pdev->dev); -+ pm_runtime_disable(&pdev->dev); -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ return 0; -+} -+ -+static struct platform_driver gsw_driver = { -+ .probe = mt7623_gsw_probe, -+ .remove = mt7623_gsw_remove, -+ .driver = { -+ .name = "mt7623-gsw", -+ .owner = THIS_MODULE, -+ .of_match_table = mediatek_gsw_match, -+ }, -+}; -+ -+module_platform_driver(gsw_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("John Crispin "); -+MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7623 SoC"); ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mt7530.c -@@ -0,0 +1,808 @@ -+/* -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * Copyright (C) 2013 John Crispin -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "mt7530.h" -+ -+#define MT7530_CPU_PORT 6 -+#define MT7530_NUM_PORTS 8 -+#define MT7530_NUM_VLANS 16 -+#define MT7530_MAX_VID 4095 -+#define MT7530_MIN_VID 0 -+ -+/* registers */ -+#define REG_ESW_VLAN_VTCR 0x90 -+#define REG_ESW_VLAN_VAWD1 0x94 -+#define REG_ESW_VLAN_VAWD2 0x98 -+#define REG_ESW_VLAN_VTIM(x) (0x100 + 4 * ((x) / 2)) -+ -+#define REG_ESW_VLAN_VAWD1_IVL_MAC BIT(30) -+#define REG_ESW_VLAN_VAWD1_VTAG_EN BIT(28) -+#define REG_ESW_VLAN_VAWD1_VALID BIT(0) -+ -+/* vlan egress mode */ -+enum { -+ ETAG_CTRL_UNTAG = 0, -+ ETAG_CTRL_TAG = 2, -+ ETAG_CTRL_SWAP = 1, -+ ETAG_CTRL_STACK = 3, -+}; -+ -+#define REG_ESW_PORT_PCR(x) (0x2004 | ((x) << 8)) -+#define REG_ESW_PORT_PVC(x) (0x2010 | ((x) << 8)) -+#define REG_ESW_PORT_PPBV1(x) (0x2014 | ((x) << 8)) -+ -+#define REG_HWTRAP 0x7804 -+ -+#define MIB_DESC(_s , _o, _n) \ -+ { \ -+ .size = (_s), \ -+ .offset = (_o), \ -+ .name = (_n), \ -+ } -+ -+struct mt7xxx_mib_desc { -+ unsigned int size; -+ unsigned int offset; -+ const char *name; -+}; -+ -+#define MT7621_MIB_COUNTER_BASE 0x4000 -+#define MT7621_MIB_COUNTER_PORT_OFFSET 0x100 -+#define MT7621_STATS_TDPC 0x00 -+#define MT7621_STATS_TCRC 0x04 -+#define MT7621_STATS_TUPC 0x08 -+#define MT7621_STATS_TMPC 0x0C -+#define MT7621_STATS_TBPC 0x10 -+#define MT7621_STATS_TCEC 0x14 -+#define MT7621_STATS_TSCEC 0x18 -+#define MT7621_STATS_TMCEC 0x1C -+#define MT7621_STATS_TDEC 0x20 -+#define MT7621_STATS_TLCEC 0x24 -+#define MT7621_STATS_TXCEC 0x28 -+#define MT7621_STATS_TPPC 0x2C -+#define MT7621_STATS_TL64PC 0x30 -+#define MT7621_STATS_TL65PC 0x34 -+#define MT7621_STATS_TL128PC 0x38 -+#define MT7621_STATS_TL256PC 0x3C -+#define MT7621_STATS_TL512PC 0x40 -+#define MT7621_STATS_TL1024PC 0x44 -+#define MT7621_STATS_TOC 0x48 -+#define MT7621_STATS_RDPC 0x60 -+#define MT7621_STATS_RFPC 0x64 -+#define MT7621_STATS_RUPC 0x68 -+#define MT7621_STATS_RMPC 0x6C -+#define MT7621_STATS_RBPC 0x70 -+#define MT7621_STATS_RAEPC 0x74 -+#define MT7621_STATS_RCEPC 0x78 -+#define MT7621_STATS_RUSPC 0x7C -+#define MT7621_STATS_RFEPC 0x80 -+#define MT7621_STATS_ROSPC 0x84 -+#define MT7621_STATS_RJEPC 0x88 -+#define MT7621_STATS_RPPC 0x8C -+#define MT7621_STATS_RL64PC 0x90 -+#define MT7621_STATS_RL65PC 0x94 -+#define MT7621_STATS_RL128PC 0x98 -+#define MT7621_STATS_RL256PC 0x9C -+#define MT7621_STATS_RL512PC 0xA0 -+#define MT7621_STATS_RL1024PC 0xA4 -+#define MT7621_STATS_ROC 0xA8 -+#define MT7621_STATS_RDPC_CTRL 0xB0 -+#define MT7621_STATS_RDPC_ING 0xB4 -+#define MT7621_STATS_RDPC_ARL 0xB8 -+ -+static const struct mt7xxx_mib_desc mt7621_mibs[] = { -+ MIB_DESC(1, MT7621_STATS_TDPC, "TxDrop"), -+ MIB_DESC(1, MT7621_STATS_TCRC, "TxCRC"), -+ MIB_DESC(1, MT7621_STATS_TUPC, "TxUni"), -+ MIB_DESC(1, MT7621_STATS_TMPC, "TxMulti"), -+ MIB_DESC(1, MT7621_STATS_TBPC, "TxBroad"), -+ MIB_DESC(1, MT7621_STATS_TCEC, "TxCollision"), -+ MIB_DESC(1, MT7621_STATS_TSCEC, "TxSingleCol"), -+ MIB_DESC(1, MT7621_STATS_TMCEC, "TxMultiCol"), -+ MIB_DESC(1, MT7621_STATS_TDEC, "TxDefer"), -+ MIB_DESC(1, MT7621_STATS_TLCEC, "TxLateCol"), -+ MIB_DESC(1, MT7621_STATS_TXCEC, "TxExcCol"), -+ MIB_DESC(1, MT7621_STATS_TPPC, "TxPause"), -+ MIB_DESC(1, MT7621_STATS_TL64PC, "Tx64Byte"), -+ MIB_DESC(1, MT7621_STATS_TL65PC, "Tx65Byte"), -+ MIB_DESC(1, MT7621_STATS_TL128PC, "Tx128Byte"), -+ MIB_DESC(1, MT7621_STATS_TL256PC, "Tx256Byte"), -+ MIB_DESC(1, MT7621_STATS_TL512PC, "Tx512Byte"), -+ MIB_DESC(1, MT7621_STATS_TL1024PC, "Tx1024Byte"), -+ MIB_DESC(2, MT7621_STATS_TOC, "TxByte"), -+ MIB_DESC(1, MT7621_STATS_RDPC, "RxDrop"), -+ MIB_DESC(1, MT7621_STATS_RFPC, "RxFiltered"), -+ MIB_DESC(1, MT7621_STATS_RUPC, "RxUni"), -+ MIB_DESC(1, MT7621_STATS_RMPC, "RxMulti"), -+ MIB_DESC(1, MT7621_STATS_RBPC, "RxBroad"), -+ MIB_DESC(1, MT7621_STATS_RAEPC, "RxAlignErr"), -+ MIB_DESC(1, MT7621_STATS_RCEPC, "RxCRC"), -+ MIB_DESC(1, MT7621_STATS_RUSPC, "RxUnderSize"), -+ MIB_DESC(1, MT7621_STATS_RFEPC, "RxFragment"), -+ MIB_DESC(1, MT7621_STATS_ROSPC, "RxOverSize"), -+ MIB_DESC(1, MT7621_STATS_RJEPC, "RxJabber"), -+ MIB_DESC(1, MT7621_STATS_RPPC, "RxPause"), -+ MIB_DESC(1, MT7621_STATS_RL64PC, "Rx64Byte"), -+ MIB_DESC(1, MT7621_STATS_RL65PC, "Rx65Byte"), -+ MIB_DESC(1, MT7621_STATS_RL128PC, "Rx128Byte"), -+ MIB_DESC(1, MT7621_STATS_RL256PC, "Rx256Byte"), -+ MIB_DESC(1, MT7621_STATS_RL512PC, "Rx512Byte"), -+ MIB_DESC(1, MT7621_STATS_RL1024PC, "Rx1024Byte"), -+ MIB_DESC(2, MT7621_STATS_ROC, "RxByte"), -+ MIB_DESC(1, MT7621_STATS_RDPC_CTRL, "RxCtrlDrop"), -+ MIB_DESC(1, MT7621_STATS_RDPC_ING, "RxIngDrop"), -+ MIB_DESC(1, MT7621_STATS_RDPC_ARL, "RxARLDrop") -+}; -+ -+enum { -+ /* Global attributes. */ -+ MT7530_ATTR_ENABLE_VLAN, -+}; -+ -+struct mt7530_port_entry { -+ u16 pvid; -+}; -+ -+struct mt7530_vlan_entry { -+ u16 vid; -+ u8 member; -+ u8 etags; -+}; -+ -+struct mt7530_priv { -+ void __iomem *base; -+ struct mii_bus *bus; -+ struct switch_dev swdev; -+ -+ bool global_vlan_enable; -+ struct mt7530_vlan_entry vlan_entries[MT7530_NUM_VLANS]; -+ struct mt7530_port_entry port_entries[MT7530_NUM_PORTS]; -+}; -+ -+struct mt7530_mapping { -+ char *name; -+ u16 pvids[MT7530_NUM_PORTS]; -+ u8 members[MT7530_NUM_VLANS]; -+ u8 etags[MT7530_NUM_VLANS]; -+ u16 vids[MT7530_NUM_VLANS]; -+} mt7530_defaults[] = { -+ { -+ .name = "llllw", -+ .pvids = { 1, 1, 1, 1, 2, 1, 1 }, -+ .members = { 0, 0x6f, 0x50 }, -+ .etags = { 0, 0x40, 0x40 }, -+ .vids = { 0, 1, 2 }, -+ }, { -+ .name = "wllll", -+ .pvids = { 2, 1, 1, 1, 1, 1, 1 }, -+ .members = { 0, 0x7e, 0x41 }, -+ .etags = { 0, 0x40, 0x40 }, -+ .vids = { 0, 1, 2 }, -+ }, -+}; -+ -+struct mt7530_mapping* -+mt7530_find_mapping(struct device_node *np) -+{ -+ const char *map; -+ int i; -+ -+ if (of_property_read_string(np, "mediatek,portmap", &map)) -+ return NULL; -+ -+ for (i = 0; i < ARRAY_SIZE(mt7530_defaults); i++) -+ if (!strcmp(map, mt7530_defaults[i].name)) -+ return &mt7530_defaults[i]; -+ -+ return NULL; -+} -+ -+static void -+mt7530_apply_mapping(struct mt7530_priv *mt7530, struct mt7530_mapping *map) -+{ -+ int i = 0; -+ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) -+ mt7530->port_entries[i].pvid = map->pvids[i]; -+ -+ for (i = 0; i < MT7530_NUM_VLANS; i++) { -+ mt7530->vlan_entries[i].member = map->members[i]; -+ mt7530->vlan_entries[i].etags = map->etags[i]; -+ mt7530->vlan_entries[i].vid = map->vids[i]; -+ } -+} -+ -+static int -+mt7530_reset_switch(struct switch_dev *dev) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ int i; -+ -+ memset(eth->port_entries, 0, sizeof(eth->port_entries)); -+ memset(eth->vlan_entries, 0, sizeof(eth->vlan_entries)); -+ -+ /* set default vid of each vlan to the same number of vlan, so the vid -+ * won't need be set explicitly. -+ */ -+ for (i = 0; i < MT7530_NUM_VLANS; i++) { -+ eth->vlan_entries[i].vid = i; -+ } -+ -+ return 0; -+} -+ -+static int -+mt7530_get_vlan_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ -+ val->value.i = eth->global_vlan_enable; -+ -+ return 0; -+} -+ -+static int -+mt7530_set_vlan_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ -+ eth->global_vlan_enable = val->value.i != 0; -+ -+ return 0; -+} -+ -+static u32 -+mt7530_r32(struct mt7530_priv *eth, u32 reg) -+{ -+ u32 val; -+ if (eth->bus) { -+ u16 high, low; -+ -+ mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff); -+ low = mdiobus_read(eth->bus, 0x1f, (reg >> 2) & 0xf); -+ high = mdiobus_read(eth->bus, 0x1f, 0x10); -+ -+ return (high << 16) | (low & 0xffff); -+ } -+ -+ val = ioread32(eth->base + reg); -+ pr_debug("MT7530 MDIO Read [%04x]=%08x\n", reg, val); -+ -+ return val; -+} -+ -+static void -+mt7530_w32(struct mt7530_priv *eth, u32 reg, u32 val) -+{ -+ if (eth->bus) { -+ mdiobus_write(eth->bus, 0x1f, 0x1f, (reg >> 6) & 0x3ff); -+ mdiobus_write(eth->bus, 0x1f, (reg >> 2) & 0xf, val & 0xffff); -+ mdiobus_write(eth->bus, 0x1f, 0x10, val >> 16); -+ return; -+ } -+ -+ pr_debug("MT7530 MDIO Write[%04x]=%08x\n", reg, val); -+ iowrite32(val, eth->base + reg); -+} -+ -+static void -+mt7530_vtcr(struct mt7530_priv *eth, u32 cmd, u32 val) -+{ -+ int i; -+ -+ mt7530_w32(eth, REG_ESW_VLAN_VTCR, BIT(31) | (cmd << 12) | val); -+ -+ for (i = 0; i < 20; i++) { -+ u32 val = mt7530_r32(eth, REG_ESW_VLAN_VTCR); -+ -+ if ((val & BIT(31)) == 0) -+ break; -+ -+ udelay(1000); -+ } -+ if (i == 20) -+ printk("mt7530: vtcr timeout\n"); -+} -+ -+static int -+mt7530_get_port_pvid(struct switch_dev *dev, int port, int *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ -+ if (port >= MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ *val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(port)); -+ *val &= 0xfff; -+ -+ return 0; -+} -+ -+static int -+mt7530_set_port_pvid(struct switch_dev *dev, int port, int pvid) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ -+ if (port >= MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ if (pvid < MT7530_MIN_VID || pvid > MT7530_MAX_VID) -+ return -EINVAL; -+ -+ eth->port_entries[port].pvid = pvid; -+ -+ return 0; -+} -+ -+static int -+mt7530_get_vlan_ports(struct switch_dev *dev, struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ u32 member; -+ u32 etags; -+ int i; -+ -+ val->len = 0; -+ -+ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS) -+ return -EINVAL; -+ -+ mt7530_vtcr(eth, 0, val->port_vlan); -+ -+ member = mt7530_r32(eth, REG_ESW_VLAN_VAWD1); -+ member >>= 16; -+ member &= 0xff; -+ -+ etags = mt7530_r32(eth, REG_ESW_VLAN_VAWD2); -+ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ struct switch_port *p; -+ int etag; -+ -+ if (!(member & BIT(i))) -+ continue; -+ -+ p = &val->value.ports[val->len++]; -+ p->id = i; -+ -+ etag = (etags >> (i * 2)) & 0x3; -+ -+ if (etag == ETAG_CTRL_TAG) -+ p->flags |= BIT(SWITCH_PORT_FLAG_TAGGED); -+ else if (etag != ETAG_CTRL_UNTAG) -+ printk("vlan egress tag control neither untag nor tag.\n"); -+ } -+ -+ return 0; -+} -+ -+static int -+mt7530_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ u8 member = 0; -+ u8 etags = 0; -+ int i; -+ -+ if (val->port_vlan < 0 || val->port_vlan >= MT7530_NUM_VLANS || -+ val->len > MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ for (i = 0; i < val->len; i++) { -+ struct switch_port *p = &val->value.ports[i]; -+ -+ if (p->id >= MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ member |= BIT(p->id); -+ -+ if (p->flags & BIT(SWITCH_PORT_FLAG_TAGGED)) -+ etags |= BIT(p->id); -+ } -+ eth->vlan_entries[val->port_vlan].member = member; -+ eth->vlan_entries[val->port_vlan].etags = etags; -+ -+ return 0; -+} -+ -+static int -+mt7530_set_vid(struct switch_dev *dev, const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ int vlan; -+ u16 vid; -+ -+ vlan = val->port_vlan; -+ vid = (u16)val->value.i; -+ -+ if (vlan < 0 || vlan >= MT7530_NUM_VLANS) -+ return -EINVAL; -+ -+ if (vid < MT7530_MIN_VID || vid > MT7530_MAX_VID) -+ return -EINVAL; -+ -+ eth->vlan_entries[vlan].vid = vid; -+ return 0; -+} -+ -+static int -+mt7530_get_vid(struct switch_dev *dev, const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ u32 vid; -+ int vlan; -+ -+ vlan = val->port_vlan; -+ -+ vid = mt7530_r32(eth, REG_ESW_VLAN_VTIM(vlan)); -+ if (vlan & 1) -+ vid = vid >> 12; -+ vid &= 0xfff; -+ -+ val->value.i = vid; -+ return 0; -+} -+ -+static int -+mt7530_apply_config(struct switch_dev *dev) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ int i, j; -+ u8 tag_ports; -+ u8 untag_ports; -+ -+ if (!eth->global_vlan_enable) { -+ for (i = 0; i < MT7530_NUM_PORTS; i++) -+ mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0000); -+ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) -+ mt7530_w32(eth, REG_ESW_PORT_PVC(i), 0x810000c0); -+ -+ return 0; -+ } -+ -+ /* set all ports as security mode */ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) -+ mt7530_w32(eth, REG_ESW_PORT_PCR(i), 0x00ff0003); -+ -+ /* check if a port is used in tag/untag vlan egress mode */ -+ tag_ports = 0; -+ untag_ports = 0; -+ -+ for (i = 0; i < MT7530_NUM_VLANS; i++) { -+ u8 member = eth->vlan_entries[i].member; -+ u8 etags = eth->vlan_entries[i].etags; -+ -+ if (!member) -+ continue; -+ -+ for (j = 0; j < MT7530_NUM_PORTS; j++) { -+ if (!(member & BIT(j))) -+ continue; -+ -+ if (etags & BIT(j)) -+ tag_ports |= 1u << j; -+ else -+ untag_ports |= 1u << j; -+ } -+ } -+ -+ /* set all untag-only ports as transparent and the rest as user port */ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ u32 pvc_mode = 0x81000000; -+ -+ if (untag_ports & BIT(i) && !(tag_ports & BIT(i))) -+ pvc_mode = 0x810000c0; -+ -+ mt7530_w32(eth, REG_ESW_PORT_PVC(i), pvc_mode); -+ } -+ -+ for (i = 0; i < MT7530_NUM_VLANS; i++) { -+ u16 vid = eth->vlan_entries[i].vid; -+ u8 member = eth->vlan_entries[i].member; -+ u8 etags = eth->vlan_entries[i].etags; -+ u32 val; -+ -+ /* vid of vlan */ -+ val = mt7530_r32(eth, REG_ESW_VLAN_VTIM(i)); -+ if (i % 2 == 0) { -+ val &= 0xfff000; -+ val |= vid; -+ } else { -+ val &= 0xfff; -+ val |= (vid << 12); -+ } -+ mt7530_w32(eth, REG_ESW_VLAN_VTIM(i), val); -+ -+ /* vlan port membership */ -+ if (member) -+ mt7530_w32(eth, REG_ESW_VLAN_VAWD1, REG_ESW_VLAN_VAWD1_IVL_MAC | -+ REG_ESW_VLAN_VAWD1_VTAG_EN | (member << 16) | -+ REG_ESW_VLAN_VAWD1_VALID); -+ else -+ mt7530_w32(eth, REG_ESW_VLAN_VAWD1, 0); -+ -+ /* egress mode */ -+ val = 0; -+ for (j = 0; j < MT7530_NUM_PORTS; j++) { -+ if (etags & BIT(j)) -+ val |= ETAG_CTRL_TAG << (j * 2); -+ else -+ val |= ETAG_CTRL_UNTAG << (j * 2); -+ } -+ mt7530_w32(eth, REG_ESW_VLAN_VAWD2, val); -+ -+ /* write to vlan table */ -+ mt7530_vtcr(eth, 1, i); -+ } -+ -+ /* Port Default PVID */ -+ for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ u32 val; -+ val = mt7530_r32(eth, REG_ESW_PORT_PPBV1(i)); -+ val &= ~0xfff; -+ val |= eth->port_entries[i].pvid; -+ mt7530_w32(eth, REG_ESW_PORT_PPBV1(i), val); -+ } -+ -+ return 0; -+} -+ -+static int -+mt7530_get_port_link(struct switch_dev *dev, int port, -+ struct switch_port_link *link) -+{ -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ u32 speed, pmsr; -+ -+ if (port < 0 || port >= MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ pmsr = mt7530_r32(eth, 0x3008 + (0x100 * port)); -+ -+ link->link = pmsr & 1; -+ link->duplex = (pmsr >> 1) & 1; -+ speed = (pmsr >> 2) & 3; -+ -+ switch (speed) { -+ case 0: -+ link->speed = SWITCH_PORT_SPEED_10; -+ break; -+ case 1: -+ link->speed = SWITCH_PORT_SPEED_100; -+ break; -+ case 2: -+ case 3: /* forced gige speed can be 2 or 3 */ -+ link->speed = SWITCH_PORT_SPEED_1000; -+ break; -+ default: -+ link->speed = SWITCH_PORT_SPEED_UNKNOWN; -+ break; -+ } -+ -+ return 0; -+} -+ -+static const struct switch_attr mt7530_global[] = { -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "enable_vlan", -+ .description = "VLAN mode (1:enabled)", -+ .max = 1, -+ .id = MT7530_ATTR_ENABLE_VLAN, -+ .get = mt7530_get_vlan_enable, -+ .set = mt7530_set_vlan_enable, -+ }, -+}; -+ -+static u64 get_mib_counter(struct mt7530_priv *eth, int i, int port) -+{ -+ unsigned int port_base; -+ u64 t; -+ -+ port_base = MT7621_MIB_COUNTER_BASE + -+ MT7621_MIB_COUNTER_PORT_OFFSET * port; -+ -+ t = mt7530_r32(eth, port_base + mt7621_mibs[i].offset); -+ if (mt7621_mibs[i].size == 2) { -+ u64 hi; -+ -+ hi = mt7530_r32(eth, port_base + mt7621_mibs[i].offset + 4); -+ t |= hi << 32; -+ } -+ -+ return t; -+} -+ -+static int mt7621_sw_get_port_mib(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ static char buf[4096]; -+ struct mt7530_priv *eth = container_of(dev, struct mt7530_priv, swdev); -+ int i, len = 0; -+ -+ if (val->port_vlan >= MT7530_NUM_PORTS) -+ return -EINVAL; -+ -+ len += snprintf(buf + len, sizeof(buf) - len, -+ "Port %d MIB counters\n", val->port_vlan); -+ -+ for (i = 0; i < sizeof(mt7621_mibs) / sizeof(*mt7621_mibs); ++i) { -+ u64 counter; -+ len += snprintf(buf + len, sizeof(buf) - len, -+ "%-11s: ", mt7621_mibs[i].name); -+ counter = get_mib_counter(eth, i, val->port_vlan); -+ len += snprintf(buf + len, sizeof(buf) - len, "%llu\n", -+ counter); -+ } -+ -+ val->value.s = buf; -+ val->len = len; -+ return 0; -+} -+ -+static const struct switch_attr mt7621_port[] = { -+ { -+ .type = SWITCH_TYPE_STRING, -+ .name = "mib", -+ .description = "Get MIB counters for port", -+ .get = mt7621_sw_get_port_mib, -+ .set = NULL, -+ }, -+}; -+ -+static const struct switch_attr mt7530_port[] = { -+}; -+ -+static const struct switch_attr mt7530_vlan[] = { -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "vid", -+ .description = "VLAN ID (0-4094)", -+ .set = mt7530_set_vid, -+ .get = mt7530_get_vid, -+ .max = 4094, -+ }, -+}; -+ -+static const struct switch_dev_ops mt7621_ops = { -+ .attr_global = { -+ .attr = mt7530_global, -+ .n_attr = ARRAY_SIZE(mt7530_global), -+ }, -+/* .attr_port = { -+ .attr = mt7621_port, -+ .n_attr = ARRAY_SIZE(mt7621_port), -+ },*/ -+ .attr_vlan = { -+ .attr = mt7530_vlan, -+ .n_attr = ARRAY_SIZE(mt7530_vlan), -+ }, -+ .get_vlan_ports = mt7530_get_vlan_ports, -+ .set_vlan_ports = mt7530_set_vlan_ports, -+ .get_port_pvid = mt7530_get_port_pvid, -+ .set_port_pvid = mt7530_set_port_pvid, -+ .get_port_link = mt7530_get_port_link, -+ .apply_config = mt7530_apply_config, -+ .reset_switch = mt7530_reset_switch, -+}; -+ -+static const struct switch_dev_ops mt7530_ops = { -+ .attr_global = { -+ .attr = mt7530_global, -+ .n_attr = ARRAY_SIZE(mt7530_global), -+ }, -+ .attr_port = { -+ .attr = mt7530_port, -+ .n_attr = ARRAY_SIZE(mt7530_port), -+ }, -+ .attr_vlan = { -+ .attr = mt7530_vlan, -+ .n_attr = ARRAY_SIZE(mt7530_vlan), -+ }, -+ .get_vlan_ports = mt7530_get_vlan_ports, -+ .set_vlan_ports = mt7530_set_vlan_ports, -+ .get_port_pvid = mt7530_get_port_pvid, -+ .set_port_pvid = mt7530_set_port_pvid, -+ .get_port_link = mt7530_get_port_link, -+ .apply_config = mt7530_apply_config, -+ .reset_switch = mt7530_reset_switch, -+}; -+ -+int -+mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan) -+{ -+ struct switch_dev *swdev; -+ struct mt7530_priv *mt7530; -+ struct mt7530_mapping *map; -+ int ret; -+ -+ mt7530 = devm_kzalloc(dev, sizeof(struct mt7530_priv), GFP_KERNEL); -+ if (!mt7530) -+ return -ENOMEM; -+ -+ mt7530->base = base; -+ mt7530->bus = bus; -+ mt7530->global_vlan_enable = vlan; -+ -+ swdev = &mt7530->swdev; -+ if (bus) { -+ swdev->alias = "mt7530"; -+ swdev->name = "mt7530"; -+ } else if (IS_ENABLED(CONFIG_MACH_MT7623)) { -+ swdev->alias = "mt7623"; -+ swdev->name = "mt7623"; -+ } else if (IS_ENABLED(CONFIG_SOC_MT7621)) { -+ swdev->alias = "mt7621"; -+ swdev->name = "mt7621"; -+ } else { -+ swdev->alias = "mt7620"; -+ swdev->name = "mt7620"; -+ } -+ swdev->cpu_port = MT7530_CPU_PORT; -+ swdev->ports = MT7530_NUM_PORTS; -+ swdev->vlans = MT7530_NUM_VLANS; -+ if (IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623)) -+ swdev->ops = &mt7621_ops; -+ else -+ swdev->ops = &mt7530_ops; -+ -+ ret = register_switch(swdev, NULL); -+ if (ret) { -+ dev_err(dev, "failed to register mt7530\n"); -+ return ret; -+ } -+ -+ mt7530_reset_switch(swdev); -+ -+ map = mt7530_find_mapping(dev->of_node); -+ if (map) -+ mt7530_apply_mapping(mt7530, map); -+ mt7530_apply_config(swdev); -+ -+ /* magic vodoo */ -+ if (!(IS_ENABLED(CONFIG_SOC_MT7621) || IS_ENABLED(CONFIG_MACH_MT7623)) && bus && mt7530_r32(mt7530, REG_HWTRAP) != 0x1117edf) { -+ dev_info(dev, "fixing up MHWTRAP register - bootloader probably played with it\n"); -+ mt7530_w32(mt7530, REG_HWTRAP, 0x1117edf); -+ } -+ dev_info(dev, "loaded %s driver\n", swdev->name); -+ -+ return 0; -+} ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mt7530.h -@@ -0,0 +1,20 @@ -+/* -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * Copyright (C) 2013 John Crispin -+ */ -+ -+#ifndef _MT7530_H__ -+#define _MT7530_H__ -+ -+int mt7530_probe(struct device *dev, void __iomem *base, struct mii_bus *bus, int vlan); -+ -+#endif ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -25,6 +25,9 @@ - - #include "mtk_eth_soc.h" - -+/* the callback used by the driver core to bringup the switch */ -+int mtk_gsw_init(struct mtk_eth *eth); -+ - static int mtk_msg_level = -1; - module_param_named(msg_level, mtk_msg_level, int, 0); - MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)"); -@@ -74,14 +77,14 @@ static int mtk_mdio_busy_wait(struct mtk - return 0; - if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT)) - break; -- usleep_range(10, 20); -+// usleep_range(10, 20); - } - - dev_err(eth->dev, "mdio: MDIO timeout\n"); - return -1; - } - --static u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, -+u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr, - u32 phy_register, u32 write_data) - { - if (mtk_mdio_busy_wait(eth)) -@@ -100,7 +103,7 @@ static u32 _mtk_mdio_write(struct mtk_et - return 0; - } - --static u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg) -+u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg) - { - u32 d; - -@@ -155,7 +158,7 @@ static void mtk_gmac0_rgmii_adjust(struc - - val = (speed == SPEED_1000) ? - RCK_CTRL_RGMII_1000 : RCK_CTRL_RGMII_10_100; -- mtk_w32(eth, val, TRGMII_RCK_CTRL); -+ mtk_w32(eth, val, _TRGMII_RCK_CTRL); - - val = (speed == SPEED_1000) ? - TCK_CTRL_RGMII_1000 : TCK_CTRL_RGMII_10_100; -@@ -1833,15 +1836,6 @@ static int mtk_hw_init(struct mtk_eth *e - } - regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val); - -- /* Set GE2 driving and slew rate */ -- regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00); -- -- /* set GE2 TDSEL */ -- regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5); -- -- /* set GE2 TUNE */ -- regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0); -- - /* GE1, Force 1000M/FD, FC ON */ - mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(0)); - -@@ -1851,6 +1845,8 @@ static int mtk_hw_init(struct mtk_eth *e - /* Enable RX VLan Offloading */ - mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); - -+ mtk_gsw_init(eth); -+ - /* disable delay and normal interrupt */ - mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); - mtk_w32(eth, 0, MTK_PDMA_DELAY_INT); -@@ -1879,6 +1875,8 @@ static int mtk_hw_init(struct mtk_eth *e - mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); - } - -+ mt7623_gsw_config(eth); -+ - return 0; - } - -@@ -2379,6 +2377,9 @@ static int mtk_probe(struct platform_dev - if (!eth) - return -ENOMEM; - -+ eth->switch_np = of_parse_phandle(pdev->dev.of_node, -+ "mediatek,switch", 0); -+ - eth->dev = &pdev->dev; - eth->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(eth->base)) ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -314,7 +314,7 @@ - MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_LINK) - - /* TRGMII RXC control register */ --#define TRGMII_RCK_CTRL 0x10300 -+#define _TRGMII_RCK_CTRL 0x10300 - #define DQSI0(x) ((x << 0) & GENMASK(6, 0)) - #define DQSI1(x) ((x << 8) & GENMASK(14, 8)) - #define RXCTL_DMWTLAT(x) ((x << 16) & GENMASK(18, 16)) -@@ -554,6 +554,9 @@ struct mtk_eth { - struct mii_bus *mii_bus; - struct work_struct pending_work; - unsigned long state; -+ -+ struct device_node *switch_np; -+ void *sw_priv; - }; - - /* struct mtk_mac - the structure that holds the info about the MACs of the -@@ -586,4 +589,6 @@ void mtk_stats_update_mac(struct mtk_mac - void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); - u32 mtk_r32(struct mtk_eth *eth, unsigned reg); - -+int mt7623_gsw_config(struct mtk_eth *eth); -+ - #endif /* MTK_ETH_H */ -- cgit v1.2.3