diff options
Diffstat (limited to 'target/linux/lantiq/patches-5.10/0026-MIPS-lantiq-Add-GPHY-Firmware-loader.patch')
-rw-r--r-- | target/linux/lantiq/patches-5.10/0026-MIPS-lantiq-Add-GPHY-Firmware-loader.patch | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/target/linux/lantiq/patches-5.10/0026-MIPS-lantiq-Add-GPHY-Firmware-loader.patch b/target/linux/lantiq/patches-5.10/0026-MIPS-lantiq-Add-GPHY-Firmware-loader.patch new file mode 100644 index 0000000000..8fd29161fe --- /dev/null +++ b/target/linux/lantiq/patches-5.10/0026-MIPS-lantiq-Add-GPHY-Firmware-loader.patch @@ -0,0 +1,352 @@ +From c8eedcadc38a5e6008d3990fbe0a5285b30335fc Mon Sep 17 00:00:00 2001 +From: Mathias Kresin <dev@kresin.me> +Date: Sun, 7 Jul 2019 21:48:56 +0200 +Subject: [PATCH] MIPS: lantiq: Add GPHY Firmware loader + +Upstream, the GPHY Firmware loader has been merged into the DSA switch +driver. But we don't use the driver yet, so bring it back. + +Signed-off-by: Mathias Kresin <dev@kresin.me> +--- + .../bindings/mips/lantiq/rcu-gphy.txt | 36 +++ + .../devicetree/bindings/mips/lantiq/rcu.txt | 18 ++ + arch/mips/configs/xway_defconfig | 1 + + arch/mips/lantiq/Kconfig | 4 + + drivers/soc/lantiq/Makefile | 1 + + drivers/soc/lantiq/gphy.c | 224 ++++++++++++++++++ + 6 files changed, 284 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mips/lantiq/rcu-gphy.txt + create mode 100644 drivers/soc/lantiq/gphy.c + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mips/lantiq/rcu-gphy.txt +@@ -0,0 +1,37 @@ ++Lantiq XWAY SoC GPHY binding ++============================ ++ ++This binding describes a software-defined ethernet PHY, provided by the RCU ++module on newer Lantiq XWAY SoCs (xRX200 and newer). ++ ++------------------------------------------------------------------------------- ++Required properties: ++- compatible : Should be one of ++ "lantiq,xrx200-gphy" ++ "lantiq,xrx200a1x-gphy" ++ "lantiq,xrx200a2x-gphy" ++ "lantiq,xrx300-gphy" ++ "lantiq,xrx330-gphy" ++- reg : Addrress of the GPHY FW load address register ++- resets : Must reference the RCU GPHY reset bit ++- reset-names : One entry, value must be "gphy" or optional "gphy2" ++- clocks : A reference to the (PMU) GPHY clock gate ++ ++Optional properties: ++- lantiq,gphy-mode : GPHY_MODE_GE (default) or GPHY_MODE_FE as defined in ++ <dt-bindings/mips/lantiq_xway_gphy.h> ++ ++ ++------------------------------------------------------------------------------- ++Example for the GPHys on the xRX200 SoCs: ++ ++#include <dt-bindings/mips/lantiq_rcu_gphy.h> ++ gphy0: gphy@20 { ++ compatible = "lantiq,xrx200a2x-gphy"; ++ reg = <0x20 0x4>; ++ ++ resets = <&reset0 31 30>, <&reset1 7 7>; ++ reset-names = "gphy", "gphy2"; ++ clocks = <&pmu0 XRX200_PMU_GATE_GPHY>; ++ lantiq,gphy-mode = <GPHY_MODE_GE>; ++ }; +--- a/Documentation/devicetree/bindings/mips/lantiq/rcu.txt ++++ b/Documentation/devicetree/bindings/mips/lantiq/rcu.txt +@@ -26,6 +26,24 @@ Example of the RCU bindings on a xRX200 + ranges = <0x0 0x203000 0x100>; + big-endian; + ++ gphy0: gphy@20 { ++ compatible = "lantiq,xrx200a2x-gphy"; ++ reg = <0x20 0x4>; ++ ++ resets = <&reset0 31 30>, <&reset1 7 7>; ++ reset-names = "gphy", "gphy2"; ++ lantiq,gphy-mode = <GPHY_MODE_GE>; ++ }; ++ ++ gphy1: gphy@68 { ++ compatible = "lantiq,xrx200a2x-gphy"; ++ reg = <0x68 0x4>; ++ ++ resets = <&reset0 29 28>, <&reset1 6 6>; ++ reset-names = "gphy", "gphy2"; ++ lantiq,gphy-mode = <GPHY_MODE_GE>; ++ }; ++ + reset0: reset-controller@10 { + compatible = "lantiq,xrx200-reset"; + reg = <0x10 4>, <0x14 4>; +--- a/arch/mips/configs/xway_defconfig ++++ b/arch/mips/configs/xway_defconfig +@@ -13,6 +13,7 @@ CONFIG_EMBEDDED=y + # CONFIG_COMPAT_BRK is not set + CONFIG_LANTIQ=y + CONFIG_PCI_LANTIQ=y ++CONFIG_XRX200_PHY_FW=y + CONFIG_CPU_MIPS32_R2=y + CONFIG_MIPS_VPE_LOADER=y + CONFIG_NR_CPUS=2 +--- a/arch/mips/lantiq/Kconfig ++++ b/arch/mips/lantiq/Kconfig +@@ -62,4 +62,8 @@ config PCIE_LANTIQ_MSI + depends on PCIE_LANTIQ && PCI_MSI + default y + ++config XRX200_PHY_FW ++ bool "XRX200 PHY firmware loader" ++ depends on SOC_XWAY ++ + endif +--- a/drivers/soc/lantiq/Makefile ++++ b/drivers/soc/lantiq/Makefile +@@ -1,2 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0-only + obj-y += fpi-bus.o ++obj-$(CONFIG_XRX200_PHY_FW) += gphy.o +--- /dev/null ++++ b/drivers/soc/lantiq/gphy.c +@@ -0,0 +1,235 @@ ++/* ++ * 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. ++ * ++ * Copyright (C) 2012 John Crispin <blogic@phrozen.org> ++ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com> ++ * Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de> ++ */ ++ ++#include <linux/clk.h> ++#include <linux/delay.h> ++#include <linux/dma-mapping.h> ++#include <linux/firmware.h> ++#include <linux/mfd/syscon.h> ++#include <linux/module.h> ++#include <linux/reboot.h> ++#include <linux/regmap.h> ++#include <linux/reset.h> ++#include <linux/of_device.h> ++#include <linux/of_platform.h> ++#include <linux/property.h> ++#include <dt-bindings/mips/lantiq_rcu_gphy.h> ++ ++#include <lantiq_soc.h> ++ ++#define XRX200_GPHY_FW_ALIGN (16 * 1024) ++ ++struct xway_gphy_priv { ++ struct clk *gphy_clk_gate; ++ struct reset_control *gphy_reset; ++ struct reset_control *gphy_reset2; ++ void __iomem *membase; ++ char *fw_name; ++}; ++ ++struct xway_gphy_match_data { ++ char *fe_firmware_name; ++ char *ge_firmware_name; ++}; ++ ++static const struct xway_gphy_match_data xrx200a1x_gphy_data = { ++ .fe_firmware_name = "lantiq/xrx200_phy22f_a14.bin", ++ .ge_firmware_name = "lantiq/xrx200_phy11g_a14.bin", ++}; ++ ++static const struct xway_gphy_match_data xrx200a2x_gphy_data = { ++ .fe_firmware_name = "lantiq/xrx200_phy22f_a22.bin", ++ .ge_firmware_name = "lantiq/xrx200_phy11g_a22.bin", ++}; ++ ++static const struct xway_gphy_match_data xrx300_gphy_data = { ++ .fe_firmware_name = "lantiq/xrx300_phy22f_a21.bin", ++ .ge_firmware_name = "lantiq/xrx300_phy11g_a21.bin", ++}; ++ ++static const struct of_device_id xway_gphy_match[] = { ++ { .compatible = "lantiq,xrx200-gphy", .data = NULL }, ++ { .compatible = "lantiq,xrx200a1x-gphy", .data = &xrx200a1x_gphy_data }, ++ { .compatible = "lantiq,xrx200a2x-gphy", .data = &xrx200a2x_gphy_data }, ++ { .compatible = "lantiq,xrx300-gphy", .data = &xrx300_gphy_data }, ++ { .compatible = "lantiq,xrx330-gphy", .data = &xrx300_gphy_data }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, xway_gphy_match); ++ ++static int xway_gphy_load(struct device *dev, struct xway_gphy_priv *priv, ++ dma_addr_t *dev_addr) ++{ ++ const struct firmware *fw; ++ void *fw_addr; ++ dma_addr_t dma_addr; ++ size_t size; ++ int ret; ++ ++ ret = request_firmware(&fw, priv->fw_name, dev); ++ if (ret) { ++ dev_err(dev, "failed to load firmware: %s, error: %i\n", ++ priv->fw_name, ret); ++ return ret; ++ } ++ ++ /* ++ * GPHY cores need the firmware code in a persistent and contiguous ++ * memory area with a 16 kB boundary aligned start address. ++ */ ++ size = fw->size + XRX200_GPHY_FW_ALIGN; ++ ++ fw_addr = dmam_alloc_coherent(dev, size, &dma_addr, GFP_KERNEL); ++ if (fw_addr) { ++ fw_addr = PTR_ALIGN(fw_addr, XRX200_GPHY_FW_ALIGN); ++ *dev_addr = ALIGN(dma_addr, XRX200_GPHY_FW_ALIGN); ++ memcpy(fw_addr, fw->data, fw->size); ++ } else { ++ dev_err(dev, "failed to alloc firmware memory\n"); ++ ret = -ENOMEM; ++ } ++ ++ release_firmware(fw); ++ ++ return ret; ++} ++ ++static int xway_gphy_of_probe(struct platform_device *pdev, ++ struct xway_gphy_priv *priv) ++{ ++ struct device *dev = &pdev->dev; ++ const struct xway_gphy_match_data *gphy_fw_name_cfg; ++ u32 gphy_mode; ++ int ret; ++ struct resource *res_gphy; ++ ++ gphy_fw_name_cfg = of_device_get_match_data(dev); ++ ++ if (of_device_is_compatible(pdev->dev.of_node, "lantiq,xrx200-gphy")) ++ switch (ltq_soc_type()) { ++ case SOC_TYPE_VR9: ++ gphy_fw_name_cfg = &xrx200a1x_gphy_data; ++ break; ++ case SOC_TYPE_VR9_2: ++ gphy_fw_name_cfg = &xrx200a2x_gphy_data; ++ break; ++ } ++ ++ priv->gphy_clk_gate = devm_clk_get(dev, NULL); ++ if (IS_ERR(priv->gphy_clk_gate)) { ++ dev_err(dev, "Failed to lookup gate clock\n"); ++ return PTR_ERR(priv->gphy_clk_gate); ++ } ++ ++ res_gphy = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->membase = devm_ioremap_resource(dev, res_gphy); ++ if (IS_ERR(priv->membase)) ++ return PTR_ERR(priv->membase); ++ ++ priv->gphy_reset = devm_reset_control_get(dev, "gphy"); ++ if (IS_ERR(priv->gphy_reset)) { ++ if (PTR_ERR(priv->gphy_reset) != -EPROBE_DEFER) ++ dev_err(dev, "Failed to lookup gphy reset\n"); ++ return PTR_ERR(priv->gphy_reset); ++ } ++ ++ priv->gphy_reset2 = devm_reset_control_get_optional(dev, "gphy2"); ++ if (IS_ERR(priv->gphy_reset2)) ++ return PTR_ERR(priv->gphy_reset2); ++ ++ ret = device_property_read_u32(dev, "lantiq,gphy-mode", &gphy_mode); ++ /* Default to GE mode */ ++ if (ret) ++ gphy_mode = GPHY_MODE_GE; ++ ++ switch (gphy_mode) { ++ case GPHY_MODE_FE: ++ priv->fw_name = gphy_fw_name_cfg->fe_firmware_name; ++ break; ++ case GPHY_MODE_GE: ++ priv->fw_name = gphy_fw_name_cfg->ge_firmware_name; ++ break; ++ default: ++ dev_err(dev, "Unknown GPHY mode %d\n", gphy_mode); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int xway_gphy_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct xway_gphy_priv *priv; ++ dma_addr_t fw_addr = 0; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ ret = xway_gphy_of_probe(pdev, priv); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(priv->gphy_clk_gate); ++ if (ret) ++ return ret; ++ ++ ret = xway_gphy_load(dev, priv, &fw_addr); ++ if (ret) { ++ clk_disable_unprepare(priv->gphy_clk_gate); ++ return ret; ++ } ++ ++ reset_control_assert(priv->gphy_reset); ++ reset_control_assert(priv->gphy_reset2); ++ ++ iowrite32be(fw_addr, priv->membase); ++ ++ reset_control_deassert(priv->gphy_reset); ++ reset_control_deassert(priv->gphy_reset2); ++ ++ platform_set_drvdata(pdev, priv); ++ ++ return ret; ++} ++ ++static int xway_gphy_remove(struct platform_device *pdev) ++{ ++ struct xway_gphy_priv *priv = platform_get_drvdata(pdev); ++ ++ iowrite32be(0, priv->membase); ++ ++ clk_disable_unprepare(priv->gphy_clk_gate); ++ ++ return 0; ++} ++ ++static struct platform_driver xway_gphy_driver = { ++ .probe = xway_gphy_probe, ++ .remove = xway_gphy_remove, ++ .driver = { ++ .name = "xway-rcu-gphy", ++ .of_match_table = xway_gphy_match, ++ }, ++}; ++ ++module_platform_driver(xway_gphy_driver); ++ ++MODULE_FIRMWARE("lantiq/xrx300_phy11g_a21.bin"); ++MODULE_FIRMWARE("lantiq/xrx300_phy22f_a21.bin"); ++MODULE_FIRMWARE("lantiq/xrx200_phy11g_a14.bin"); ++MODULE_FIRMWARE("lantiq/xrx200_phy11g_a22.bin"); ++MODULE_FIRMWARE("lantiq/xrx200_phy22f_a14.bin"); ++MODULE_FIRMWARE("lantiq/xrx200_phy22f_a22.bin"); ++MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); ++MODULE_DESCRIPTION("Lantiq XWAY GPHY Firmware Loader"); ++MODULE_LICENSE("GPL"); |