diff --git a/projects/Allwinner/devices/H6/patches/linux/07-opi3.patch b/projects/Allwinner/devices/H6/patches/linux/07-opi3.patch index 6d9689e4e4..bbfc2b929a 100644 --- a/projects/Allwinner/devices/H6/patches/linux/07-opi3.patch +++ b/projects/Allwinner/devices/H6/patches/linux/07-opi3.patch @@ -1040,259 +1040,6 @@ index 58a6635c909e3..f795362f5b77e 100644 &r_i2c { -From d996492e1f700a9f0a104c50b126a022dee77dd6 Mon Sep 17 00:00:00 2001 -From: Icenowy Zheng -Date: Mon, 25 Dec 2017 12:04:02 +0800 -Subject: [PATCH 20/34] phy: allwinner: add phy driver for USB3 PHY on - Allwinner H6 SoC - -Allwinner H6 SoC contains a USB3 PHY (with USB2 DP/DM lines also -controlled). - -Add a driver for it. - -The register operations in this driver is mainly extracted from the BSP -USB3 driver. - -Signed-off-by: Icenowy Zheng -Reviewed-by: Chen-Yu Tsai ---- - drivers/phy/allwinner/Kconfig | 12 ++ - drivers/phy/allwinner/Makefile | 1 + - drivers/phy/allwinner/phy-sun50i-usb3.c | 194 ++++++++++++++++++++++++ - 3 files changed, 207 insertions(+) - create mode 100644 drivers/phy/allwinner/phy-sun50i-usb3.c - -diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig -index fb1204bcc4548..2c363db177f20 100644 ---- a/drivers/phy/allwinner/Kconfig -+++ b/drivers/phy/allwinner/Kconfig -@@ -41,3 +41,15 @@ config PHY_SUN9I_USB - sun9i SoCs. - - This driver controls each individual USB 2 host PHY. -+ -+config PHY_SUN50I_USB3 -+ tristate "Allwinner sun50i SoC USB3 PHY driver" -+ depends on ARCH_SUNXI && HAS_IOMEM && OF -+ depends on RESET_CONTROLLER -+ select USB_COMMON -+ select GENERIC_PHY -+ help -+ Enable this to support the USB3.0-capable transceiver that is -+ part of some Allwinner sun50i SoCs. -+ -+ This driver controls each individual USB 2+3 host PHY combo. -diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile -index 7d0053efbfaa6..59575a895779b 100644 ---- a/drivers/phy/allwinner/Makefile -+++ b/drivers/phy/allwinner/Makefile -@@ -1,3 +1,4 @@ - obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o - obj-$(CONFIG_PHY_SUN6I_MIPI_DPHY) += phy-sun6i-mipi-dphy.o - obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o -+obj-$(CONFIG_PHY_SUN50I_USB3) += phy-sun50i-usb3.o -diff --git a/drivers/phy/allwinner/phy-sun50i-usb3.c b/drivers/phy/allwinner/phy-sun50i-usb3.c -new file mode 100644 -index 0000000000000..226c99c2d664c ---- /dev/null -+++ b/drivers/phy/allwinner/phy-sun50i-usb3.c -@@ -0,0 +1,194 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Allwinner sun50i(H6) USB 3.0 phy driver -+ * -+ * Copyright (C) 2017 Icenowy Zheng -+ * -+ * Based on phy-sun9i-usb.c, which is: -+ * -+ * Copyright (C) 2014-2015 Chen-Yu Tsai -+ * -+ * Based on code from Allwinner BSP, which is: -+ * -+ * Copyright (c) 2010-2015 Allwinner Technology Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Interface Status and Control Registers */ -+#define SUNXI_ISCR 0x00 -+#define SUNXI_PIPE_CLOCK_CONTROL 0x14 -+#define SUNXI_PHY_TUNE_LOW 0x18 -+#define SUNXI_PHY_TUNE_HIGH 0x1c -+#define SUNXI_PHY_EXTERNAL_CONTROL 0x20 -+ -+/* USB2.0 Interface Status and Control Register */ -+#define SUNXI_ISCR_FORCE_VBUS (3 << 12) -+ -+/* PIPE Clock Control Register */ -+#define SUNXI_PCC_PIPE_CLK_OPEN (1 << 6) -+ -+/* PHY External Control Register */ -+#define SUNXI_PEC_EXTERN_VBUS (3 << 1) -+#define SUNXI_PEC_SSC_EN (1 << 24) -+#define SUNXI_PEC_REF_SSP_EN (1 << 26) -+ -+/* PHY Tune High Register */ -+#define SUNXI_TX_DEEMPH_3P5DB(n) ((n) << 19) -+#define SUNXI_TX_DEEMPH_3P5DB_MASK GENMASK(24, 19) -+#define SUNXI_TX_DEEMPH_6DB(n) ((n) << 13) -+#define SUNXI_TX_DEEMPH_6GB_MASK GENMASK(18, 13) -+#define SUNXI_TX_SWING_FULL(n) ((n) << 6) -+#define SUNXI_TX_SWING_FULL_MASK GENMASK(12, 6) -+#define SUNXI_LOS_BIAS(n) ((n) << 3) -+#define SUNXI_LOS_BIAS_MASK GENMASK(5, 3) -+#define SUNXI_TXVBOOSTLVL(n) ((n) << 0) -+#define SUNXI_TXVBOOSTLVL_MASK GENMASK(0, 2) -+ -+struct sun50i_usb3_phy { -+ struct phy *phy; -+ void __iomem *regs; -+ struct reset_control *reset; -+ struct clk *clk; -+}; -+ -+static void sun50i_usb3_phy_open(struct sun50i_usb3_phy *phy) -+{ -+ u32 val; -+ -+ val = readl(phy->regs + SUNXI_PHY_EXTERNAL_CONTROL); -+ val |= SUNXI_PEC_EXTERN_VBUS; -+ val |= SUNXI_PEC_SSC_EN | SUNXI_PEC_REF_SSP_EN; -+ writel(val, phy->regs + SUNXI_PHY_EXTERNAL_CONTROL); -+ -+ val = readl(phy->regs + SUNXI_PIPE_CLOCK_CONTROL); -+ val |= SUNXI_PCC_PIPE_CLK_OPEN; -+ writel(val, phy->regs + SUNXI_PIPE_CLOCK_CONTROL); -+ -+ val = readl(phy->regs + SUNXI_ISCR); -+ val |= SUNXI_ISCR_FORCE_VBUS; -+ writel(val, phy->regs + SUNXI_ISCR); -+ -+ /* -+ * All the magic numbers written to the PHY_TUNE_{LOW_HIGH} -+ * registers are directly taken from the BSP USB3 driver from -+ * Allwiner. -+ */ -+ writel(0x0047fc87, phy->regs + SUNXI_PHY_TUNE_LOW); -+ -+ val = readl(phy->regs + SUNXI_PHY_TUNE_HIGH); -+ val &= ~(SUNXI_TXVBOOSTLVL_MASK | SUNXI_LOS_BIAS_MASK | -+ SUNXI_TX_SWING_FULL_MASK | SUNXI_TX_DEEMPH_6GB_MASK | -+ SUNXI_TX_DEEMPH_3P5DB_MASK); -+ val |= SUNXI_TXVBOOSTLVL(0x7); -+ val |= SUNXI_LOS_BIAS(0x7); -+ val |= SUNXI_TX_SWING_FULL(0x55); -+ val |= SUNXI_TX_DEEMPH_6DB(0x20); -+ val |= SUNXI_TX_DEEMPH_3P5DB(0x15); -+ writel(val, phy->regs + SUNXI_PHY_TUNE_HIGH); -+} -+ -+static int sun50i_usb3_phy_init(struct phy *_phy) -+{ -+ struct sun50i_usb3_phy *phy = phy_get_drvdata(_phy); -+ int ret; -+ -+ ret = clk_prepare_enable(phy->clk); -+ if (ret) -+ goto err_clk; -+ -+ ret = reset_control_deassert(phy->reset); -+ if (ret) -+ goto err_reset; -+ -+ sun50i_usb3_phy_open(phy); -+ return 0; -+ -+err_reset: -+ clk_disable_unprepare(phy->clk); -+ -+err_clk: -+ return ret; -+} -+ -+static int sun50i_usb3_phy_exit(struct phy *_phy) -+{ -+ struct sun50i_usb3_phy *phy = phy_get_drvdata(_phy); -+ -+ reset_control_assert(phy->reset); -+ clk_disable_unprepare(phy->clk); -+ -+ return 0; -+} -+ -+static const struct phy_ops sun50i_usb3_phy_ops = { -+ .init = sun50i_usb3_phy_init, -+ .exit = sun50i_usb3_phy_exit, -+ .owner = THIS_MODULE, -+}; -+ -+static int sun50i_usb3_phy_probe(struct platform_device *pdev) -+{ -+ struct sun50i_usb3_phy *phy; -+ struct device *dev = &pdev->dev; -+ struct phy_provider *phy_provider; -+ struct resource *res; -+ -+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); -+ if (!phy) -+ return -ENOMEM; -+ -+ phy->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(phy->clk)) { -+ dev_err(dev, "failed to get phy clock\n"); -+ return PTR_ERR(phy->clk); -+ } -+ -+ phy->reset = devm_reset_control_get(dev, NULL); -+ if (IS_ERR(phy->reset)) { -+ dev_err(dev, "failed to get reset control\n"); -+ return PTR_ERR(phy->reset); -+ } -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ phy->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(phy->regs)) -+ return PTR_ERR(phy->regs); -+ -+ phy->phy = devm_phy_create(dev, NULL, &sun50i_usb3_phy_ops); -+ if (IS_ERR(phy->phy)) { -+ dev_err(dev, "failed to create PHY\n"); -+ return PTR_ERR(phy->phy); -+ } -+ -+ phy_set_drvdata(phy->phy, phy); -+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); -+ -+ return PTR_ERR_OR_ZERO(phy_provider); -+} -+ -+static const struct of_device_id sun50i_usb3_phy_of_match[] = { -+ { .compatible = "allwinner,sun50i-h6-usb3-phy" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, sun50i_usb3_phy_of_match); -+ -+static struct platform_driver sun50i_usb3_phy_driver = { -+ .probe = sun50i_usb3_phy_probe, -+ .driver = { -+ .of_match_table = sun50i_usb3_phy_of_match, -+ .name = "sun50i-usb3-phy", -+ } -+}; -+module_platform_driver(sun50i_usb3_phy_driver); -+ -+MODULE_DESCRIPTION("Allwinner sun50i USB 3.0 phy driver"); -+MODULE_AUTHOR("Icenowy Zheng "); -+MODULE_LICENSE("GPL"); - From 5fd2d3bd956cc875d07433454f18dcbc14e120d5 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Tue, 26 Mar 2019 15:14:14 +0100 diff --git a/projects/Allwinner/linux/linux.arm.conf b/projects/Allwinner/linux/linux.arm.conf index c0d6495b30..0a00501b8b 100644 --- a/projects/Allwinner/linux/linux.arm.conf +++ b/projects/Allwinner/linux/linux.arm.conf @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 5.1.5 Kernel Configuration +# Linux/arm 5.1.9 Kernel Configuration # # @@ -4632,6 +4632,7 @@ CONFIG_GENERIC_PHY_MIPI_DPHY=y CONFIG_PHY_SUN4I_USB=y CONFIG_PHY_SUN6I_MIPI_DPHY=y CONFIG_PHY_SUN9I_USB=y +CONFIG_PHY_SUN50I_USB3=y # CONFIG_BCM_KONA_USB2_PHY is not set # CONFIG_PHY_CADENCE_DP is not set # CONFIG_PHY_CADENCE_DPHY is not set diff --git a/projects/Allwinner/patches/linux/0012-H6-USB3.patch b/projects/Allwinner/patches/linux/0012-H6-USB3.patch new file mode 100644 index 0000000000..49c10afe6d --- /dev/null +++ b/projects/Allwinner/patches/linux/0012-H6-USB3.patch @@ -0,0 +1,252 @@ +From d996492e1f700a9f0a104c50b126a022dee77dd6 Mon Sep 17 00:00:00 2001 +From: Icenowy Zheng +Date: Mon, 25 Dec 2017 12:04:02 +0800 +Subject: [PATCH 20/34] phy: allwinner: add phy driver for USB3 PHY on + Allwinner H6 SoC + +Allwinner H6 SoC contains a USB3 PHY (with USB2 DP/DM lines also +controlled). + +Add a driver for it. + +The register operations in this driver is mainly extracted from the BSP +USB3 driver. + +Signed-off-by: Icenowy Zheng +Reviewed-by: Chen-Yu Tsai +--- + drivers/phy/allwinner/Kconfig | 12 ++ + drivers/phy/allwinner/Makefile | 1 + + drivers/phy/allwinner/phy-sun50i-usb3.c | 194 ++++++++++++++++++++++++ + 3 files changed, 207 insertions(+) + create mode 100644 drivers/phy/allwinner/phy-sun50i-usb3.c + +diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig +index fb1204bcc4548..2c363db177f20 100644 +--- a/drivers/phy/allwinner/Kconfig ++++ b/drivers/phy/allwinner/Kconfig +@@ -41,3 +41,15 @@ config PHY_SUN9I_USB + sun9i SoCs. + + This driver controls each individual USB 2 host PHY. ++ ++config PHY_SUN50I_USB3 ++ tristate "Allwinner sun50i SoC USB3 PHY driver" ++ depends on ARCH_SUNXI && HAS_IOMEM && OF ++ depends on RESET_CONTROLLER ++ select USB_COMMON ++ select GENERIC_PHY ++ help ++ Enable this to support the USB3.0-capable transceiver that is ++ part of some Allwinner sun50i SoCs. ++ ++ This driver controls each individual USB 2+3 host PHY combo. +diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile +index 7d0053efbfaa6..59575a895779b 100644 +--- a/drivers/phy/allwinner/Makefile ++++ b/drivers/phy/allwinner/Makefile +@@ -1,3 +1,4 @@ + obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o + obj-$(CONFIG_PHY_SUN6I_MIPI_DPHY) += phy-sun6i-mipi-dphy.o + obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o ++obj-$(CONFIG_PHY_SUN50I_USB3) += phy-sun50i-usb3.o +diff --git a/drivers/phy/allwinner/phy-sun50i-usb3.c b/drivers/phy/allwinner/phy-sun50i-usb3.c +new file mode 100644 +index 0000000000000..226c99c2d664c +--- /dev/null ++++ b/drivers/phy/allwinner/phy-sun50i-usb3.c +@@ -0,0 +1,194 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Allwinner sun50i(H6) USB 3.0 phy driver ++ * ++ * Copyright (C) 2017 Icenowy Zheng ++ * ++ * Based on phy-sun9i-usb.c, which is: ++ * ++ * Copyright (C) 2014-2015 Chen-Yu Tsai ++ * ++ * Based on code from Allwinner BSP, which is: ++ * ++ * Copyright (c) 2010-2015 Allwinner Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Interface Status and Control Registers */ ++#define SUNXI_ISCR 0x00 ++#define SUNXI_PIPE_CLOCK_CONTROL 0x14 ++#define SUNXI_PHY_TUNE_LOW 0x18 ++#define SUNXI_PHY_TUNE_HIGH 0x1c ++#define SUNXI_PHY_EXTERNAL_CONTROL 0x20 ++ ++/* USB2.0 Interface Status and Control Register */ ++#define SUNXI_ISCR_FORCE_VBUS (3 << 12) ++ ++/* PIPE Clock Control Register */ ++#define SUNXI_PCC_PIPE_CLK_OPEN (1 << 6) ++ ++/* PHY External Control Register */ ++#define SUNXI_PEC_EXTERN_VBUS (3 << 1) ++#define SUNXI_PEC_SSC_EN (1 << 24) ++#define SUNXI_PEC_REF_SSP_EN (1 << 26) ++ ++/* PHY Tune High Register */ ++#define SUNXI_TX_DEEMPH_3P5DB(n) ((n) << 19) ++#define SUNXI_TX_DEEMPH_3P5DB_MASK GENMASK(24, 19) ++#define SUNXI_TX_DEEMPH_6DB(n) ((n) << 13) ++#define SUNXI_TX_DEEMPH_6GB_MASK GENMASK(18, 13) ++#define SUNXI_TX_SWING_FULL(n) ((n) << 6) ++#define SUNXI_TX_SWING_FULL_MASK GENMASK(12, 6) ++#define SUNXI_LOS_BIAS(n) ((n) << 3) ++#define SUNXI_LOS_BIAS_MASK GENMASK(5, 3) ++#define SUNXI_TXVBOOSTLVL(n) ((n) << 0) ++#define SUNXI_TXVBOOSTLVL_MASK GENMASK(0, 2) ++ ++struct sun50i_usb3_phy { ++ struct phy *phy; ++ void __iomem *regs; ++ struct reset_control *reset; ++ struct clk *clk; ++}; ++ ++static void sun50i_usb3_phy_open(struct sun50i_usb3_phy *phy) ++{ ++ u32 val; ++ ++ val = readl(phy->regs + SUNXI_PHY_EXTERNAL_CONTROL); ++ val |= SUNXI_PEC_EXTERN_VBUS; ++ val |= SUNXI_PEC_SSC_EN | SUNXI_PEC_REF_SSP_EN; ++ writel(val, phy->regs + SUNXI_PHY_EXTERNAL_CONTROL); ++ ++ val = readl(phy->regs + SUNXI_PIPE_CLOCK_CONTROL); ++ val |= SUNXI_PCC_PIPE_CLK_OPEN; ++ writel(val, phy->regs + SUNXI_PIPE_CLOCK_CONTROL); ++ ++ val = readl(phy->regs + SUNXI_ISCR); ++ val |= SUNXI_ISCR_FORCE_VBUS; ++ writel(val, phy->regs + SUNXI_ISCR); ++ ++ /* ++ * All the magic numbers written to the PHY_TUNE_{LOW_HIGH} ++ * registers are directly taken from the BSP USB3 driver from ++ * Allwiner. ++ */ ++ writel(0x0047fc87, phy->regs + SUNXI_PHY_TUNE_LOW); ++ ++ val = readl(phy->regs + SUNXI_PHY_TUNE_HIGH); ++ val &= ~(SUNXI_TXVBOOSTLVL_MASK | SUNXI_LOS_BIAS_MASK | ++ SUNXI_TX_SWING_FULL_MASK | SUNXI_TX_DEEMPH_6GB_MASK | ++ SUNXI_TX_DEEMPH_3P5DB_MASK); ++ val |= SUNXI_TXVBOOSTLVL(0x7); ++ val |= SUNXI_LOS_BIAS(0x7); ++ val |= SUNXI_TX_SWING_FULL(0x55); ++ val |= SUNXI_TX_DEEMPH_6DB(0x20); ++ val |= SUNXI_TX_DEEMPH_3P5DB(0x15); ++ writel(val, phy->regs + SUNXI_PHY_TUNE_HIGH); ++} ++ ++static int sun50i_usb3_phy_init(struct phy *_phy) ++{ ++ struct sun50i_usb3_phy *phy = phy_get_drvdata(_phy); ++ int ret; ++ ++ ret = clk_prepare_enable(phy->clk); ++ if (ret) ++ goto err_clk; ++ ++ ret = reset_control_deassert(phy->reset); ++ if (ret) ++ goto err_reset; ++ ++ sun50i_usb3_phy_open(phy); ++ return 0; ++ ++err_reset: ++ clk_disable_unprepare(phy->clk); ++ ++err_clk: ++ return ret; ++} ++ ++static int sun50i_usb3_phy_exit(struct phy *_phy) ++{ ++ struct sun50i_usb3_phy *phy = phy_get_drvdata(_phy); ++ ++ reset_control_assert(phy->reset); ++ clk_disable_unprepare(phy->clk); ++ ++ return 0; ++} ++ ++static const struct phy_ops sun50i_usb3_phy_ops = { ++ .init = sun50i_usb3_phy_init, ++ .exit = sun50i_usb3_phy_exit, ++ .owner = THIS_MODULE, ++}; ++ ++static int sun50i_usb3_phy_probe(struct platform_device *pdev) ++{ ++ struct sun50i_usb3_phy *phy; ++ struct device *dev = &pdev->dev; ++ struct phy_provider *phy_provider; ++ struct resource *res; ++ ++ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); ++ if (!phy) ++ return -ENOMEM; ++ ++ phy->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(phy->clk)) { ++ dev_err(dev, "failed to get phy clock\n"); ++ return PTR_ERR(phy->clk); ++ } ++ ++ phy->reset = devm_reset_control_get(dev, NULL); ++ if (IS_ERR(phy->reset)) { ++ dev_err(dev, "failed to get reset control\n"); ++ return PTR_ERR(phy->reset); ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ phy->regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(phy->regs)) ++ return PTR_ERR(phy->regs); ++ ++ phy->phy = devm_phy_create(dev, NULL, &sun50i_usb3_phy_ops); ++ if (IS_ERR(phy->phy)) { ++ dev_err(dev, "failed to create PHY\n"); ++ return PTR_ERR(phy->phy); ++ } ++ ++ phy_set_drvdata(phy->phy, phy); ++ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ ++ return PTR_ERR_OR_ZERO(phy_provider); ++} ++ ++static const struct of_device_id sun50i_usb3_phy_of_match[] = { ++ { .compatible = "allwinner,sun50i-h6-usb3-phy" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, sun50i_usb3_phy_of_match); ++ ++static struct platform_driver sun50i_usb3_phy_driver = { ++ .probe = sun50i_usb3_phy_probe, ++ .driver = { ++ .of_match_table = sun50i_usb3_phy_of_match, ++ .name = "sun50i-usb3-phy", ++ } ++}; ++module_platform_driver(sun50i_usb3_phy_driver); ++ ++MODULE_DESCRIPTION("Allwinner sun50i USB 3.0 phy driver"); ++MODULE_AUTHOR("Icenowy Zheng "); ++MODULE_LICENSE("GPL");