This driver is derived from this Linux driver:
linux/drivers/phy/ralink/phy-ralink-usb.c

The driver sets up power and host mode, but also needs to configure PHY
registers for the MT7628 and MT7688.

I removed the reset controller handling for the USB host and device, as
it does not seem to be necessary right now. The soft reset bits for both
devices are enabled by default and testing has shown (with hackish
reset handling added), that USB related commands work identical with
or without the reset handling.

Please note that the resulting USB support is tested only very minimal.
I was able to detect one of my 3 currently available USB sticks.
Perhaps some further work is needed to fully support the EHCI controller
integrated in the MT76x8 SoC.

Signed-off-by: Stefan Roese <[email protected]>
Cc: Marek Vasut <[email protected]>
Cc: Daniel Schwierzeck <[email protected]>
---
 drivers/phy/Kconfig          |   8 ++
 drivers/phy/Makefile         |   1 +
 drivers/phy/mt76x8-usb-phy.c | 161 +++++++++++++++++++++++++++++++++++
 3 files changed, 170 insertions(+)
 create mode 100644 drivers/phy/mt76x8-usb-phy.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 32bbf41dd1..102fb91fff 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -174,4 +174,12 @@ config KEYSTONE_USB_PHY
 
          This PHY is found on some Keystone (K2) devices supporting USB.
 
+config MT76X8_USB_PHY
+       bool "MediaTek MT76x8 (7628/88) USB PHY support"
+       depends on PHY
+       help
+          Support the USB PHY in MT76x8 SoCs
+
+         This PHY is found on MT76x8 devices supporting USB.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 099551d693..b55917bce1 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o 
meson-gxl-usb3.o
 obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o
 obj-$(CONFIG_OMAP_USB2_PHY) += omap-usb2-phy.o
 obj-$(CONFIG_KEYSTONE_USB_PHY) += keystone-usb-phy.o
+obj-$(CONFIG_MT76X8_USB_PHY) += mt76x8-usb-phy.o
diff --git a/drivers/phy/mt76x8-usb-phy.c b/drivers/phy/mt76x8-usb-phy.c
new file mode 100644
index 0000000000..268da8ef6c
--- /dev/null
+++ b/drivers/phy/mt76x8-usb-phy.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Stefan Roese <[email protected]>
+ *
+ * Derived from linux/drivers/phy/ralink/phy-ralink-usb.c
+ *     Copyright (C) 2017 John Crispin <[email protected]>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <reset-uclass.h>
+#include <syscon.h>
+#include <asm/io.h>
+
+#define RT_SYSC_REG_SYSCFG1            0x014
+#define RT_SYSC_REG_CLKCFG1            0x030
+#define RT_SYSC_REG_USB_PHY_CFG                0x05c
+
+#define OFS_U2_PHY_AC0                 0x800
+#define OFS_U2_PHY_AC1                 0x804
+#define OFS_U2_PHY_AC2                 0x808
+#define OFS_U2_PHY_ACR0                        0x810
+#define OFS_U2_PHY_ACR1                        0x814
+#define OFS_U2_PHY_ACR2                        0x818
+#define OFS_U2_PHY_ACR3                        0x81C
+#define OFS_U2_PHY_ACR4                        0x820
+#define OFS_U2_PHY_AMON0               0x824
+#define OFS_U2_PHY_DCR0                        0x860
+#define OFS_U2_PHY_DCR1                        0x864
+#define OFS_U2_PHY_DTM0                        0x868
+#define OFS_U2_PHY_DTM1                        0x86C
+
+#define RT_RSTCTRL_UDEV                        BIT(25)
+#define RT_RSTCTRL_UHST                        BIT(22)
+#define RT_SYSCFG1_USB0_HOST_MODE      BIT(10)
+
+#define MT7620_CLKCFG1_UPHY0_CLK_EN    BIT(25)
+#define MT7620_CLKCFG1_UPHY1_CLK_EN    BIT(22)
+#define RT_CLKCFG1_UPHY1_CLK_EN                BIT(20)
+#define RT_CLKCFG1_UPHY0_CLK_EN                BIT(18)
+
+#define USB_PHY_UTMI_8B60M             BIT(1)
+#define UDEV_WAKEUP                    BIT(0)
+
+struct mt76x8_usb_phy {
+       u32                     clk;
+       void __iomem            *base;
+       struct regmap           *sysctl;
+};
+
+static void u2_phy_w32(struct mt76x8_usb_phy *phy, u32 val, u32 reg)
+{
+       writel(val, phy->base + reg);
+}
+
+static u32 u2_phy_r32(struct mt76x8_usb_phy *phy, u32 reg)
+{
+       return readl(phy->base + reg);
+}
+
+static void mt76x8_usb_phy_init(struct mt76x8_usb_phy *phy)
+{
+       u2_phy_r32(phy, OFS_U2_PHY_AC2);
+       u2_phy_r32(phy, OFS_U2_PHY_ACR0);
+       u2_phy_r32(phy, OFS_U2_PHY_DCR0);
+
+       u2_phy_w32(phy, 0x00ffff02, OFS_U2_PHY_DCR0);
+       u2_phy_r32(phy, OFS_U2_PHY_DCR0);
+       u2_phy_w32(phy, 0x00555502, OFS_U2_PHY_DCR0);
+       u2_phy_r32(phy, OFS_U2_PHY_DCR0);
+       u2_phy_w32(phy, 0x00aaaa02, OFS_U2_PHY_DCR0);
+       u2_phy_r32(phy, OFS_U2_PHY_DCR0);
+       u2_phy_w32(phy, 0x00000402, OFS_U2_PHY_DCR0);
+       u2_phy_r32(phy, OFS_U2_PHY_DCR0);
+       u2_phy_w32(phy, 0x0048086a, OFS_U2_PHY_AC0);
+       u2_phy_w32(phy, 0x4400001c, OFS_U2_PHY_AC1);
+       u2_phy_w32(phy, 0xc0200000, OFS_U2_PHY_ACR3);
+       u2_phy_w32(phy, 0x02000000, OFS_U2_PHY_DTM0);
+}
+
+static int mt76x8_usb_phy_power_on(struct phy *_phy)
+{
+       struct mt76x8_usb_phy *phy = dev_get_priv(_phy->dev);
+       u32 t;
+
+       /* enable the phy */
+       regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1,
+                          phy->clk, phy->clk);
+
+       /* setup host mode */
+       regmap_update_bits(phy->sysctl, RT_SYSC_REG_SYSCFG1,
+                          RT_SYSCFG1_USB0_HOST_MODE,
+                          RT_SYSCFG1_USB0_HOST_MODE);
+
+       /*
+        * The SDK kernel had a delay of 100ms. however on device
+        * testing showed that 10ms is enough
+        */
+       mdelay(10);
+
+       if (phy->base)
+               mt76x8_usb_phy_init(phy);
+
+       /* print some status info */
+       regmap_read(phy->sysctl, RT_SYSC_REG_USB_PHY_CFG, &t);
+       printf("remote usb device wakeup %s\n",
+              (t & UDEV_WAKEUP) ? "enabled" : "disabled");
+       if (t & USB_PHY_UTMI_8B60M)
+               printf("UTMI 8bit 60MHz\n");
+       else
+               printf("UTMI 16bit 30MHz\n");
+
+       return 0;
+}
+
+static int mt76x8_usb_phy_power_off(struct phy *_phy)
+{
+       struct mt76x8_usb_phy *phy = dev_get_priv(_phy->dev);
+
+       /* disable the phy */
+       regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1,
+                          phy->clk, 0);
+
+       return 0;
+}
+
+static int mt76x8_usb_phy_probe(struct udevice *dev)
+{
+       struct mt76x8_usb_phy *phy = dev_get_priv(dev);
+
+       phy->sysctl = syscon_regmap_lookup_by_phandle(dev, "ralink,sysctl");
+       if (IS_ERR(phy->sysctl))
+               return PTR_ERR(phy->sysctl);
+
+       phy->base = dev_read_addr_ptr(dev);
+       if (!phy->base)
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct phy_ops mt76x8_usb_phy_ops = {
+       .power_on = mt76x8_usb_phy_power_on,
+       .power_off = mt76x8_usb_phy_power_off,
+};
+
+static const struct udevice_id mt76x8_usb_phy_ids[] = {
+       { .compatible = "mediatek,mt7628-usbphy" },
+       { }
+};
+
+U_BOOT_DRIVER(mt76x8_usb_phy) = {
+       .name           = "mt76x8_usb_phy",
+       .id             = UCLASS_PHY,
+       .of_match       = mt76x8_usb_phy_ids,
+       .ops            = &mt76x8_usb_phy_ops,
+       .probe          = mt76x8_usb_phy_probe,
+       .priv_auto_alloc_size = sizeof(struct mt76x8_usb_phy),
+};
-- 
2.21.0

_______________________________________________
U-Boot mailing list
[email protected]
https://lists.denx.de/listinfo/u-boot

Reply via email to