author: leyfoon.tan <leyfoon.tan@starfivetech.com> 2022-11-07 07:11:22 +0000
committer: leyfoon.tan <leyfoon.tan@starfivetech.com> 2022-11-07 07:11:22 +0000
commit: 0f9fd42752277456a1f324b773877ac28aa9290b
parent: fce77eb3dae41d6bc32dee28e5a184674b1e425e
Commit Summary:
Diffstat:
16 files changed, 521 insertions, 48 deletions
diff --git a/Documentation/devicetree/bindings/net/starfive,dwmac-plat.yaml b/Documentation/devicetree/bindings/net/starfive,dwmac-plat.yaml
new file mode 100644
index 000000000000..19c2cf72501a
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/starfive,dwmac-plat.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/starfive,dwmac-plat.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive DWMAC glue layer Device Tree Bindings
+
+maintainers:
+ - Tan Chun Hau <chunhau.tan@starfivetech.com>
+
+select:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - starfive,dwmac
+ required:
+ - compatible
+
+allOf:
+ - $ref: "snps,dwmac.yaml#"
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - starfive,dwmac
+ - const: snps,dwmac-5.10a
+
+ clocks:
+ items:
+ - description: Gtx clock
+ - description: Tx clock
+ - description: PTP reference clock
+ - description: GMAC main clock
+ - description: PTP reference clock
+ - description: Gtxc clock
+
+ clock-names:
+ items:
+ - const: gtx
+ - const: tx
+ - const: ptp_ref
+ - const: stmmaceth
+ - const: pclk
+ - const: gtxc
+
+required:
+ - compatible
+ - clocks
+ - clock-names
+
+unevaluatedProperties: false
+
+Example:
+ - |
+ #include <dt-bindings/reset/starfive-jh7110.h>
+ #include <dt-bindings/clock/starfive-jh7110-clkgen.h>
+
+ /* gmac device configuration */
+ stmmac_axi_setup: stmmac-axi-config {
+ snps,wr_osr_lmt = <0xf>;
+ snps,rd_osr_lmt = <0xf>;
+ snps,blen = <256 128 64 32 0 0 0>;
+ };
+
+ gmac0: gmac@17020000 {
+ compatible = "starfive,dwmac","snps,dwmac-5.10a";
+ reg = <0x0 0x17020000 0x0 0x10000>;
+ interrupts = <7>, <6>, <5>;
+ interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
+ phy-reset-gpios = <&gpio 63 0>;
+ clock-names = "gtx",
+ "tx",
+ "ptp_ref",
+ "stmmaceth",
+ "pclk",
+ "gtxc";
+ clocks = <&clkgen JH7110_GMAC0_GTXCLK>,
+ <&clkgen JH7110_U0_GMAC5_CLK_TX>,
+ <&clkgen JH7110_GMAC0_PTP>,
+ <&clkgen JH7110_U0_GMAC5_CLK_AHB>,
+ <&clkgen JH7110_U0_GMAC5_CLK_AXI>,
+ <&clkgen JH7110_GMAC0_GTXC>;
+ resets = <&rstgen RSTN_U0_DW_GMAC5_AXI64_AHB>,
+ <&rstgen RSTN_U0_DW_GMAC5_AXI64_AXI>;
+ reset-names = "ahb", "stmmaceth";
+ max-frame-size = <1500>;
+ phy-mode = "rgmii-id";
+ snps,multicast-filter-bins = <64>;
+ snps,perfect-filter-entries = <128>;
+ rx-fifo-depth = <2048>;
+ tx-fifo-depth = <2048>;
+ snps,fixed-burst;
+ snps,no-pbl-x8;
+ snps,force_thresh_dma_mode;
+ snps,axi-config = <&stmmac_axi_setup>;
+ snps,tso;
+ snps,en-tx-lpi-clockgating;
+ snps,txpbl = <4>;
+ snps,rxpbl = <4>;
+ };
diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs
index 4ea8d3c28658..ba81328edb01 100644
--- a/arch/riscv/Kconfig.socs
+++ b/arch/riscv/Kconfig.socs
@@ -32,6 +32,7 @@ config SOC_STARFIVE
config SOC_STARFIVE_DUBHE
bool "StarFive Dubhe SoC"
+ select RISCV_DMA_NONCOHERENT
select SERIAL_SIFIVE if TTY
select SERIAL_SIFIVE_CONSOLE if TTY
select SIFIVE_PLIC
diff --git a/arch/riscv/boot/dts/starfive/dubhe.dtsi b/arch/riscv/boot/dts/starfive/dubhe.dtsi
index 73e0090fb7b1..a0506d46134a 100644
--- a/arch/riscv/boot/dts/starfive/dubhe.dtsi
+++ b/arch/riscv/boot/dts/starfive/dubhe.dtsi
@@ -124,6 +124,40 @@
status = "disabled";
};
+ stmmac_axi_setup: stmmac-axi-config {
+ snps,wr_osr_lmt = <0xf>;
+ snps,rd_osr_lmt = <0xf>;
+ snps,blen = <256 128 64 32 0 0 0>;
+ };
+
+ gmac0: gmac@10100000 {
+ compatible = "starfive,dwmac","snps,dwmac-5.10a";
+ reg = <0x0 0x10100000 0x0 0x10000>;
+ clock-names = "gtx",
+ "tx",
+ "ptp_ref",
+ "stmmaceth",
+ "pclk",
+ "gtxc";
+ interrupt-parent = <&plic0>;
+ interrupts = <8>, <11>, <12>;
+ interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
+ max-frame-size = <1500>;
+ snps,multicast-filter-bins = <64>;
+ snps,perfect-filter-entries = <8>;
+ rx-fifo-depth = <2048>;
+ tx-fifo-depth = <2048>;
+ snps,fixed-burst;
+ snps,no-pbl-x8;
+ snps,force_thresh_dma_mode;
+ snps,axi-config = <&stmmac_axi_setup>;
+ snps,tso;
+ snps,en-tx-lpi-clockgating;
+ snps,txpbl = <4>;
+ snps,rxpbl = <4>;
+ status = "disabled";
+ };
+
pmu {
compatible = "riscv,pmu";
riscv,event-to-mhpmevent = <0x00005 0x0000 0x1B>,
diff --git a/arch/riscv/boot/dts/starfive/dubhe_fpga.dts b/arch/riscv/boot/dts/starfive/dubhe_fpga.dts
index dce02d6ccd96..4563628bd389 100644
--- a/arch/riscv/boot/dts/starfive/dubhe_fpga.dts
+++ b/arch/riscv/boot/dts/starfive/dubhe_fpga.dts
@@ -7,11 +7,12 @@
model = "StarFive Dubhe FPGA";
aliases {
+ ethernet0 = &gmac0;
serial0 = &uart0;
};
chosen {
- bootargs = "console=ttySIF0,115200 earlycon=sbi";
+ bootargs = "console=ttySIF0,115200 earlycon=sbi root=/dev/nfs nfsroot=192.168.153.221:/home/nfsroot,rw,tcp,vers=3 ip=192.168.152.100:192.168.153.221:192.168.152.1:255.255.255.0::eth0:off";
};
cpus {
@@ -25,6 +26,40 @@
};
soc {
+
+ fpga_2p5mhz_clk: fpga_2p5mhz_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <2500000>;
+ };
+
+ fpga_50mhz_clk: fpga_50mhz_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+};
+
+&gmac0 {
+ status = "okay";
+ phy-mode = "rgmii-id";
+ phy-handle = <ðernet_phy0>;
+ clocks = <&fpga_2p5mhz_clk>,
+ <&fpga_2p5mhz_clk>,
+ <&fpga_2p5mhz_clk>,
+ <&fpga_50mhz_clk>,
+ <&fpga_50mhz_clk>,
+ <&fpga_2p5mhz_clk>;
+
+ mdio0 {
+ compatible = "snps,dwmac-mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ethernet_phy0: ethernet-phy@0 {
+ reg = <0>;
+ max-speed = <10>;
+ };
};
};
diff --git a/arch/riscv/configs/starfive_dubhe_defconfig b/arch/riscv/configs/starfive_dubhe_defconfig
index 524ca5ceb076..4b584aa243a6 100644
--- a/arch/riscv/configs/starfive_dubhe_defconfig
+++ b/arch/riscv/configs/starfive_dubhe_defconfig
@@ -13,11 +13,10 @@ CONFIG_CGROUP_BPF=y
CONFIG_NAMESPACES=y
CONFIG_USER_NS=y
CONFIG_CHECKPOINT_RESTORE=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="rootfs.cpio"
CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_PERF_EVENTS=y
+CONFIG_RISCV_UNCACHED_OFFSET=0x400000000
CONFIG_SOC_STARFIVE_DUBHE=y
CONFIG_SMP=y
CONFIG_HOTPLUG_CPU=y
@@ -37,6 +36,33 @@ CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_ACCT=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_TABLES=y
+CONFIG_NFT_CT=y
+CONFIG_NFT_COMPAT=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_IPCOMP=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_DUP_IPV4=y
+CONFIG_NFT_FIB_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_NETLINK_DIAG=y
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
@@ -51,6 +77,10 @@ CONFIG_SCSI_VIRTIO=y
CONFIG_NETDEVICES=y
CONFIG_VIRTIO_NET=y
CONFIG_MACB=y
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_SELFTESTS=y
+CONFIG_DWMAC_STARFIVE_PLAT=y
+CONFIG_MARVELL_PHY=y
CONFIG_MICROSEMI_PHY=y
CONFIG_REALTEK_PHY=y
CONFIG_INPUT_MOUSEDEV=y
@@ -82,7 +112,6 @@ CONFIG_VIRTIO_MMIO=y
CONFIG_GOLDFISH=y
CONFIG_RPMSG_CHAR=y
CONFIG_RPMSG_VIRTIO=y
-CONFIG_RESET_CONTROLLER=y
CONFIG_AUTOFS4_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
@@ -109,8 +138,6 @@ CONFIG_NLS_CODEPAGE_1251=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=y
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CRYPTO_DEV_VIRTIO=y
CONFIG_CRC16=y
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
index 5ddec9c4e204..ce93f6cd8c7d 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -29,6 +29,7 @@ enum sbi_ext_id {
SBI_EXT_HSM = 0x48534D,
SBI_EXT_SRST = 0x53525354,
SBI_EXT_PMU = 0x504D55,
+ SBI_EXT_CACHE = 0x09057485,
};
enum sbi_ext_base_fid {
@@ -96,6 +97,11 @@ enum sbi_ext_pmu_fid {
SBI_EXT_PMU_COUNTER_FW_READ,
};
+enum sbi_ext_cache_fid {
+ SBI_EXT_BASE_L2_FLUSH = 0,
+ SBI_EXT_BASE_L2_INVALIDATE,
+};
+
#define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(55, 0)
#define RISCV_PMU_RAW_EVENT_IDX 0x20000
@@ -240,6 +246,8 @@ int sbi_remote_hfence_vvma_asid(const unsigned long *hart_mask,
unsigned long size,
unsigned long asid);
int sbi_probe_extension(int ext);
+int sbi_cache_invalidate(unsigned long start, unsigned long len);
+int sbi_cache_flush(unsigned long start, unsigned long len);
/* Check if current SBI specification version is 0.1 or not */
static inline int sbi_spec_is_0_1(void)
diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c
index eac30382f79e..5cab4d24ea03 100644
--- a/arch/riscv/kernel/sbi.c
+++ b/arch/riscv/kernel/sbi.c
@@ -605,6 +605,35 @@ static const struct riscv_ipi_ops sbi_ipi_ops = {
.ipi_inject = sbi_send_cpumask_ipi
};
+int sbi_cache_flush(unsigned long start, unsigned long len)
+{
+ struct sbiret ret;
+
+ ret = sbi_ecall(SBI_EXT_CACHE, SBI_EXT_BASE_L2_FLUSH,
+ start, len, 0, 0, 0, 0);
+ if (!ret.error)
+ if (ret.value)
+ return ret.value;
+
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL(sbi_cache_flush);
+
+int sbi_cache_invalidate(unsigned long start, unsigned long len)
+{
+
+ struct sbiret ret;
+
+ ret = sbi_ecall(SBI_EXT_CACHE, SBI_EXT_BASE_L2_INVALIDATE,
+ start, len, 0, 0, 0, 0);
+ if (!ret.error)
+ if (ret.value)
+ return ret.value;
+
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL(sbi_cache_invalidate);
+
void __init sbi_init(void)
{
int ret;
diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c
index 868dd02945fc..c1f7c5c21095 100644
--- a/arch/riscv/mm/dma-noncoherent.c
+++ b/arch/riscv/mm/dma-noncoherent.c
@@ -14,6 +14,62 @@
#include <asm/sbi.h>
#include <asm/smp.h>
+#ifdef CONFIG_SOC_STARFIVE_DUBHE
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size, enum dma_data_direction dir)
+{
+ sbi_cache_flush(paddr, size);
+}
+
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, enum dma_data_direction dir)
+{
+ switch (dir) {
+ case DMA_BIDIRECTIONAL:
+ sbi_cache_flush(paddr, size);
+ break;
+ case DMA_FROM_DEVICE:
+ sbi_cache_invalidate(paddr, size);
+ break;
+ case DMA_TO_DEVICE:
+ break;
+ default:
+ BUG();
+ }
+}
+
+void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
+ const struct iommu_ops *iommu, bool coherent)
+{
+ dev_info(dev, "coherent device %d dev->dma_coherent %d\n", coherent, dev->dma_coherent);
+ dev->dma_coherent = coherent;
+}
+
+void arch_dma_prep_coherent(struct page *page, size_t size)
+{
+ void *flush_addr = page_address(page);
+
+ sbi_cache_flush(__pa(flush_addr), size);
+}
+
+void arch_dma_clear_uncached(void *addr, size_t size)
+{
+ memunmap(addr);
+}
+
+void *arch_dma_set_uncached(void *addr, size_t size)
+{
+ phys_addr_t phys_addr = __pa(addr) + CONFIG_RISCV_UNCACHED_OFFSET;
+ void *mem_base = NULL;
+
+ mem_base = memremap(phys_addr, size, MEMREMAP_WT);
+ if (!mem_base) {
+ pr_err("%s memremap failed for addr %px\n", __func__, addr);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return mem_base;
+}
+
+#else
//TODO Do it through SBI
#include <soc/sifive/sifive_l2_cache.h>
@@ -61,3 +117,4 @@ void *arch_dma_set_uncached(void *addr, size_t size)
return mem_base;
}
+#endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 929cfc22cd0c..41bafd5cac80 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -232,6 +232,17 @@ config DWMAC_INTEL_PLAT
the stmmac device driver. This driver is used for the Intel Keem Bay
SoC.
+config DWMAC_STARFIVE_PLAT
+ tristate "StarFive dwmac support"
+ depends on OF && COMMON_CLK
+ depends on STMMAC_ETH
+ help
+ Support for ethernet controllers on StarFive SoCs
+
+ This selects the StarFive platform specific glue layer support for
+ the stmmac device driver. This driver is used for the StarFive JH8100
+ SoC.
+
config DWMAC_VISCONTI
tristate "Toshiba Visconti DWMAC support"
default ARCH_VISCONTI
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index d4e12e9ace4f..1df002c07f79 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o
obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o
obj-$(CONFIG_DWMAC_INTEL_PLAT) += dwmac-intel-plat.o
+obj-$(CONFIG_DWMAC_STARFIVE_PLAT) += dwmac-starfive-plat.o
obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o
obj-$(CONFIG_DWMAC_IMX8) += dwmac-imx.o
obj-$(CONFIG_DWMAC_VISCONTI) += dwmac-visconti.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive-plat.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive-plat.c
new file mode 100644
index 000000000000..a6248cd0bde9
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive-plat.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/* StarFive DWMAC platform driver
+ *
+ * Copyright(C) 2022 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/of_device.h>
+#include "stmmac_platform.h"
+
+struct starfive_dwmac {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk_tx;
+ struct clk *clk_gtx;
+ struct clk *clk_gtxc;
+};
+
+static void starfive_eth_fix_mac_speed(void *priv, unsigned int speed)
+{
+ struct starfive_dwmac *dwmac = priv;
+ unsigned long rate;
+ int err;
+
+ switch (speed) {
+ case SPEED_1000:
+ rate = 125000000;
+ break;
+ case SPEED_100:
+ rate = 25000000;
+ break;
+ case SPEED_10:
+ rate = 2500000;
+ break;
+ default:
+ dev_err(dwmac->dev, "invalid speed %u\n", speed);
+ return;
+ }
+
+ err = clk_set_rate(dwmac->clk_gtx, rate);
+ if (err < 0)
+ dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate);
+}
+
+static const struct of_device_id starfive_eth_plat_match[] = {
+ { .compatible = "starfive,dwmac"},
+ { }
+};
+
+static int starfive_eth_plat_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct plat_stmmacenet_data *plat_dat;
+ struct stmmac_resources stmmac_res;
+ struct starfive_dwmac *dwmac;
+ int err;
+
+ err = stmmac_get_platform_resources(pdev, &stmmac_res);
+ if (err)
+ return err;
+
+ plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
+ if (IS_ERR(plat_dat)) {
+ dev_err(&pdev->dev, "dt configuration failed\n");
+ return PTR_ERR(plat_dat);
+ }
+
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+ return -ENOMEM;
+
+ dwmac->dev = &pdev->dev;
+ dwmac->regs = stmmac_res.addr;
+
+ if (!is_of_node(dev->fwnode))
+ goto bypass_clk_reset_gpio;
+
+ dwmac->clk_tx = devm_clk_get(&pdev->dev, "tx");
+ if (IS_ERR(dwmac->clk_tx)) {
+ err = PTR_ERR(dwmac->clk_tx);
+ goto err;
+ }
+
+ err = clk_prepare_enable(dwmac->clk_tx);
+ if (err < 0)
+ goto err;
+
+ dwmac->clk_gtx = devm_clk_get(&pdev->dev, "gtx");
+ if (IS_ERR(dwmac->clk_gtx)) {
+ err = PTR_ERR(dwmac->clk_gtx);
+ goto disable_tx;
+ }
+
+ err = clk_prepare_enable(dwmac->clk_gtx);
+ if (err < 0)
+ goto disable_tx;
+
+ dwmac->clk_gtxc = devm_clk_get(&pdev->dev, "gtxc");
+ if (IS_ERR(dwmac->clk_gtxc)) {
+ err = PTR_ERR(dwmac->clk_gtxc);
+ goto disable_gtx;
+ }
+
+ err = clk_prepare_enable(dwmac->clk_gtxc);
+ if (err < 0)
+ goto disable_gtx;
+
+ err = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ if (err)
+ goto err;
+
+bypass_clk_reset_gpio:
+ plat_dat->fix_mac_speed = starfive_eth_fix_mac_speed;
+ plat_dat->init = NULL;
+ plat_dat->bsp_priv = dwmac;
+ return 0;
+
+disable_gtx:
+ clk_disable_unprepare(dwmac->clk_gtx);
+disable_tx:
+ clk_disable_unprepare(dwmac->clk_tx);
+err:
+ stmmac_remove_config_dt(pdev, plat_dat);
+ return err;
+}
+
+static int starfive_eth_plat_remove(struct platform_device *pdev)
+{
+ struct starfive_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
+
+ clk_disable_unprepare(dwmac->clk_gtxc);
+ clk_disable_unprepare(dwmac->clk_gtx);
+ clk_disable_unprepare(dwmac->clk_tx);
+
+ return 0;
+}
+
+static struct platform_driver starfive_eth_plat_driver = {
+ .probe = starfive_eth_plat_probe,
+ .remove = starfive_eth_plat_remove,
+ .driver = {
+ .name = "starfive-eth-plat",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = starfive_eth_plat_match,
+ },
+};
+
+module_platform_driver(starfive_eth_plat_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("StarFive DWMAC platform driver");
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index d6916bee1694..3422f0746d82 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1463,16 +1463,14 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i];
if (!buf->page) {
- buf->page = page_pool_alloc_pages(rx_q->page_pool,
- GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32);
+ buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
if (!buf->page)
return -ENOMEM;
buf->page_offset = stmmac_rx_offset(priv);
}
if (priv->sph && !buf->sec_page) {
- buf->sec_page = page_pool_alloc_pages(rx_q->page_pool,
- GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32);
+ buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool);
if (!buf->sec_page)
return -ENOMEM;
@@ -4488,15 +4486,13 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
p = rx_q->dma_rx + entry;
if (!buf->page) {
- buf->page = page_pool_alloc_pages(rx_q->page_pool,
- GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32);
+ buf->page = page_pool_dev_alloc_pages(rx_q->page_pool);
if (!buf->page)
break;
}
if (priv->sph && !buf->sec_page) {
- buf->sec_page = page_pool_alloc_pages(rx_q->page_pool,
- GFP_ATOMIC | __GFP_NOWARN | GFP_DMA32);
+ buf->sec_page = page_pool_dev_alloc_pages(rx_q->page_pool);
if (!buf->sec_page)
break;
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 7de631f5356f..f94161637ea8 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -955,23 +955,7 @@ static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode,
if (phylink_autoneg_inband(mode))
return;
- switch (speed) {
- case SPEED_1000:
- val = BMCR_SPEED1000;
- break;
- case SPEED_100:
- val = BMCR_SPEED100;
- break;
- case SPEED_10:
- val = BMCR_SPEED10;
- break;
- default:
- return;
- }
-
- if (duplex == DUPLEX_FULL)
- val |= BMCR_FULLDPLX;
-
+ val = mii_bmcr_encode_fixed(speed, duplex);
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val);
if (ret)
pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret));
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 4fcfca4e1702..541f784981a1 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -189,6 +189,8 @@
#define MII_88E1510_GEN_CTRL_REG_1_MODE_RGMII_SGMII 0x4
#define MII_88E1510_GEN_CTRL_REG_1_RESET 0x8000 /* Soft reset */
+#define MII_88E1510_MSCR_2 0x15
+
#define MII_VCT5_TX_RX_MDI0_COUPLING 0x10
#define MII_VCT5_TX_RX_MDI1_COUPLING 0x11
#define MII_VCT5_TX_RX_MDI2_COUPLING 0x12
@@ -551,9 +553,9 @@ static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
else
mscr = 0;
- return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
- MII_88E1121_PHY_MSCR_REG,
- MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
+ return phy_modify_paged_changed(phydev, MII_MARVELL_MSCR_PAGE,
+ MII_88E1121_PHY_MSCR_REG,
+ MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
}
static int m88e1121_config_aneg(struct phy_device *phydev)
@@ -567,11 +569,13 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
return err;
}
+ changed = err;
+
err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
if (err < 0)
return err;
- changed = err;
+ changed |= err;
err = genphy_config_aneg(phydev);
if (err < 0)
@@ -1173,7 +1177,44 @@ static int m88e1318_config_init(struct phy_device *phydev)
static int m88e1510_config_init(struct phy_device *phydev)
{
+ static const struct {
+ u16 reg17, reg16;
+ } errata_vals[] = {
+ { 0x214b, 0x2144 },
+ { 0x0c28, 0x2146 },
+ { 0xb233, 0x214d },
+ { 0xcc0c, 0x2159 },
+ };
int err;
+ int i;
+
+ /* As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512/
+ * 88E1514 Rev A0, Errata Section 5.1:
+ * If EEE is intended to be used, the following register writes
+ * must be done once after every hardware reset.
+ */
+ err = marvell_set_page(phydev, 0x00FF);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(errata_vals); ++i) {
+ err = phy_write(phydev, 17, errata_vals[i].reg17);
+ if (err)
+ return err;
+ err = phy_write(phydev, 16, errata_vals[i].reg16);
+ if (err)
+ return err;
+ }
+
+ err = marvell_set_page(phydev, 0x00FB);
+ if (err < 0)
+ return err;
+ err = phy_write(phydev, 07, 0xC00D);
+ if (err < 0)
+ return err;
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
+ if (err < 0)
+ return err;
/* SGMII-to-Copper mode initialization */
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
@@ -1932,6 +1973,52 @@ static void marvell_get_stats(struct phy_device *phydev,
data[i] = marvell_get_stat(phydev, i);
}
+static int m88e1510_loopback(struct phy_device *phydev, bool enable)
+{
+ int err;
+
+ if (enable) {
+ u16 bmcr_ctl, mscr2_ctl = 0;
+
+ bmcr_ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);
+
+ err = phy_write(phydev, MII_BMCR, bmcr_ctl);
+ if (err < 0)
+ return err;
+
+ if (phydev->speed == SPEED_1000)
+ mscr2_ctl = BMCR_SPEED1000;
+ else if (phydev->speed == SPEED_100)
+ mscr2_ctl = BMCR_SPEED100;
+
+ err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
+ MII_88E1510_MSCR_2, BMCR_SPEED1000 |
+ BMCR_SPEED100, mscr2_ctl);
+ if (err < 0)
+ return err;
+
+ /* Need soft reset to have speed configuration takes effect */
+ err = genphy_soft_reset(phydev);
+ if (err < 0)
+ return err;
+
+ /* FIXME: Based on trial and error test, it seem 1G need to have
+ * delay between soft reset and loopback enablement.
+ */
+ if (phydev->speed == SPEED_1000)
+ msleep(1000);
+
+ return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
+ BMCR_LOOPBACK);
+ } else {
+ err = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, 0);
+ if (err < 0)
+ return err;
+
+ return phy_config_aneg(phydev);
+ }
+}
+
static int marvell_vct5_wait_complete(struct phy_device *phydev)
{
int i;
@@ -3078,7 +3165,7 @@ static struct phy_driver marvell_drivers[] = {
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
- .set_loopback = genphy_loopback,
+ .set_loopback = m88e1510_loopback,
.get_tunable = m88e1011_get_tunable,
.set_tunable = m88e1011_set_tunable,
.cable_test_start = marvell_vct7_cable_test_start,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 4f9990b47a37..5544d3ee3aba 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2001,18 +2001,12 @@ EXPORT_SYMBOL(genphy_config_eee_advert);
*/
int genphy_setup_forced(struct phy_device *phydev)
{
- u16 ctl = 0;
+ u16 ctl;
phydev->pause = 0;
phydev->asym_pause = 0;
- if (SPEED_1000 == phydev->speed)
- ctl |= BMCR_SPEED1000;
- else if (SPEED_100 == phydev->speed)
- ctl |= BMCR_SPEED100;
-
- if (DUPLEX_FULL == phydev->duplex)
- ctl |= BMCR_FULLDPLX;
+ ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);
return phy_modify(phydev, MII_BMCR,
~(BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN), ctl);
@@ -2615,13 +2609,7 @@ int genphy_loopback(struct phy_device *phydev, bool enable)
u16 val, ctl = BMCR_LOOPBACK;
int ret;
- if (phydev->speed == SPEED_1000)
- ctl |= BMCR_SPEED1000;
- else if (phydev->speed == SPEED_100)
- ctl |= BMCR_SPEED100;
-
- if (phydev->duplex == DUPLEX_FULL)
- ctl |= BMCR_FULLDPLX;
+ ctl |= mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);
phy_modify(phydev, MII_BMCR, ~0, ctl);
diff --git a/include/linux/mii.h b/include/linux/mii.h
index 12ea29e04293..599b56766a51 100644
--- a/include/linux/mii.h
+++ b/include/linux/mii.h
@@ -595,4 +595,39 @@ static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
return cap;
}
+/**
+ * mii_bmcr_encode_fixed - encode fixed speed/duplex settings to a BMCR value
+ * @speed: a SPEED_* value
+ * @duplex: a DUPLEX_* value
+ *
+ * Encode the speed and duplex to a BMCR value. 2500, 1000, 100 and 10 Mbps are
+ * supported. 2500Mbps is encoded to 1000Mbps. Other speeds are encoded as 10
+ * Mbps. Unknown duplex values are encoded to half-duplex.
+ */
+static inline u16 mii_bmcr_encode_fixed(int speed, int duplex)
+{
+ u16 bmcr;
+
+ switch (speed) {
+ case SPEED_2500:
+ case SPEED_1000:
+ bmcr = BMCR_SPEED1000;
+ break;
+
+ case SPEED_100:
+ bmcr = BMCR_SPEED100;
+ break;
+
+ case SPEED_10:
+ default:
+ bmcr = BMCR_SPEED10;
+ break;
+ }
+
+ if (duplex == DUPLEX_FULL)
+ bmcr |= BMCR_FULLDPLX;
+
+ return bmcr;
+}
+
#endif /* __LINUX_MII_H__ */