Commit d7d7606c7e3f78fa201280f5af08ddae238233a1

Authored by Stefan Roese
Committed by Daniel Schwierzeck
1 parent 484d15f32f

phy: Add USB PHY driver for the MT76x8 (7628/7688) SoC

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 <sr@denx.de>
Cc: Marek Vasut <marex@denx.de>
Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>

Showing 3 changed files with 170 additions and 0 deletions Side-by-side Diff

... ... @@ -174,5 +174,13 @@
174 174  
175 175 This PHY is found on some Keystone (K2) devices supporting USB.
176 176  
  177 +config MT76X8_USB_PHY
  178 + bool "MediaTek MT76x8 (7628/88) USB PHY support"
  179 + depends on PHY
  180 + help
  181 + Support the USB PHY in MT76x8 SoCs
  182 +
  183 + This PHY is found on MT76x8 devices supporting USB.
  184 +
177 185 endmenu
drivers/phy/Makefile
... ... @@ -19,4 +19,5 @@
19 19 obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o
20 20 obj-$(CONFIG_OMAP_USB2_PHY) += omap-usb2-phy.o
21 21 obj-$(CONFIG_KEYSTONE_USB_PHY) += keystone-usb-phy.o
  22 +obj-$(CONFIG_MT76X8_USB_PHY) += mt76x8-usb-phy.o
drivers/phy/mt76x8-usb-phy.c
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +/*
  3 + * Copyright (C) 2019 Stefan Roese <sr@denx.de>
  4 + *
  5 + * Derived from linux/drivers/phy/ralink/phy-ralink-usb.c
  6 + * Copyright (C) 2017 John Crispin <john@phrozen.org>
  7 + */
  8 +
  9 +#include <common.h>
  10 +#include <dm.h>
  11 +#include <generic-phy.h>
  12 +#include <regmap.h>
  13 +#include <reset-uclass.h>
  14 +#include <syscon.h>
  15 +#include <asm/io.h>
  16 +
  17 +#define RT_SYSC_REG_SYSCFG1 0x014
  18 +#define RT_SYSC_REG_CLKCFG1 0x030
  19 +#define RT_SYSC_REG_USB_PHY_CFG 0x05c
  20 +
  21 +#define OFS_U2_PHY_AC0 0x800
  22 +#define OFS_U2_PHY_AC1 0x804
  23 +#define OFS_U2_PHY_AC2 0x808
  24 +#define OFS_U2_PHY_ACR0 0x810
  25 +#define OFS_U2_PHY_ACR1 0x814
  26 +#define OFS_U2_PHY_ACR2 0x818
  27 +#define OFS_U2_PHY_ACR3 0x81C
  28 +#define OFS_U2_PHY_ACR4 0x820
  29 +#define OFS_U2_PHY_AMON0 0x824
  30 +#define OFS_U2_PHY_DCR0 0x860
  31 +#define OFS_U2_PHY_DCR1 0x864
  32 +#define OFS_U2_PHY_DTM0 0x868
  33 +#define OFS_U2_PHY_DTM1 0x86C
  34 +
  35 +#define RT_RSTCTRL_UDEV BIT(25)
  36 +#define RT_RSTCTRL_UHST BIT(22)
  37 +#define RT_SYSCFG1_USB0_HOST_MODE BIT(10)
  38 +
  39 +#define MT7620_CLKCFG1_UPHY0_CLK_EN BIT(25)
  40 +#define MT7620_CLKCFG1_UPHY1_CLK_EN BIT(22)
  41 +#define RT_CLKCFG1_UPHY1_CLK_EN BIT(20)
  42 +#define RT_CLKCFG1_UPHY0_CLK_EN BIT(18)
  43 +
  44 +#define USB_PHY_UTMI_8B60M BIT(1)
  45 +#define UDEV_WAKEUP BIT(0)
  46 +
  47 +struct mt76x8_usb_phy {
  48 + u32 clk;
  49 + void __iomem *base;
  50 + struct regmap *sysctl;
  51 +};
  52 +
  53 +static void u2_phy_w32(struct mt76x8_usb_phy *phy, u32 val, u32 reg)
  54 +{
  55 + writel(val, phy->base + reg);
  56 +}
  57 +
  58 +static u32 u2_phy_r32(struct mt76x8_usb_phy *phy, u32 reg)
  59 +{
  60 + return readl(phy->base + reg);
  61 +}
  62 +
  63 +static void mt76x8_usb_phy_init(struct mt76x8_usb_phy *phy)
  64 +{
  65 + u2_phy_r32(phy, OFS_U2_PHY_AC2);
  66 + u2_phy_r32(phy, OFS_U2_PHY_ACR0);
  67 + u2_phy_r32(phy, OFS_U2_PHY_DCR0);
  68 +
  69 + u2_phy_w32(phy, 0x00ffff02, OFS_U2_PHY_DCR0);
  70 + u2_phy_r32(phy, OFS_U2_PHY_DCR0);
  71 + u2_phy_w32(phy, 0x00555502, OFS_U2_PHY_DCR0);
  72 + u2_phy_r32(phy, OFS_U2_PHY_DCR0);
  73 + u2_phy_w32(phy, 0x00aaaa02, OFS_U2_PHY_DCR0);
  74 + u2_phy_r32(phy, OFS_U2_PHY_DCR0);
  75 + u2_phy_w32(phy, 0x00000402, OFS_U2_PHY_DCR0);
  76 + u2_phy_r32(phy, OFS_U2_PHY_DCR0);
  77 + u2_phy_w32(phy, 0x0048086a, OFS_U2_PHY_AC0);
  78 + u2_phy_w32(phy, 0x4400001c, OFS_U2_PHY_AC1);
  79 + u2_phy_w32(phy, 0xc0200000, OFS_U2_PHY_ACR3);
  80 + u2_phy_w32(phy, 0x02000000, OFS_U2_PHY_DTM0);
  81 +}
  82 +
  83 +static int mt76x8_usb_phy_power_on(struct phy *_phy)
  84 +{
  85 + struct mt76x8_usb_phy *phy = dev_get_priv(_phy->dev);
  86 + u32 t;
  87 +
  88 + /* enable the phy */
  89 + regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1,
  90 + phy->clk, phy->clk);
  91 +
  92 + /* setup host mode */
  93 + regmap_update_bits(phy->sysctl, RT_SYSC_REG_SYSCFG1,
  94 + RT_SYSCFG1_USB0_HOST_MODE,
  95 + RT_SYSCFG1_USB0_HOST_MODE);
  96 +
  97 + /*
  98 + * The SDK kernel had a delay of 100ms. however on device
  99 + * testing showed that 10ms is enough
  100 + */
  101 + mdelay(10);
  102 +
  103 + if (phy->base)
  104 + mt76x8_usb_phy_init(phy);
  105 +
  106 + /* print some status info */
  107 + regmap_read(phy->sysctl, RT_SYSC_REG_USB_PHY_CFG, &t);
  108 + printf("remote usb device wakeup %s\n",
  109 + (t & UDEV_WAKEUP) ? "enabled" : "disabled");
  110 + if (t & USB_PHY_UTMI_8B60M)
  111 + printf("UTMI 8bit 60MHz\n");
  112 + else
  113 + printf("UTMI 16bit 30MHz\n");
  114 +
  115 + return 0;
  116 +}
  117 +
  118 +static int mt76x8_usb_phy_power_off(struct phy *_phy)
  119 +{
  120 + struct mt76x8_usb_phy *phy = dev_get_priv(_phy->dev);
  121 +
  122 + /* disable the phy */
  123 + regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1,
  124 + phy->clk, 0);
  125 +
  126 + return 0;
  127 +}
  128 +
  129 +static int mt76x8_usb_phy_probe(struct udevice *dev)
  130 +{
  131 + struct mt76x8_usb_phy *phy = dev_get_priv(dev);
  132 +
  133 + phy->sysctl = syscon_regmap_lookup_by_phandle(dev, "ralink,sysctl");
  134 + if (IS_ERR(phy->sysctl))
  135 + return PTR_ERR(phy->sysctl);
  136 +
  137 + phy->base = dev_read_addr_ptr(dev);
  138 + if (!phy->base)
  139 + return -EINVAL;
  140 +
  141 + return 0;
  142 +}
  143 +
  144 +static struct phy_ops mt76x8_usb_phy_ops = {
  145 + .power_on = mt76x8_usb_phy_power_on,
  146 + .power_off = mt76x8_usb_phy_power_off,
  147 +};
  148 +
  149 +static const struct udevice_id mt76x8_usb_phy_ids[] = {
  150 + { .compatible = "mediatek,mt7628-usbphy" },
  151 + { }
  152 +};
  153 +
  154 +U_BOOT_DRIVER(mt76x8_usb_phy) = {
  155 + .name = "mt76x8_usb_phy",
  156 + .id = UCLASS_PHY,
  157 + .of_match = mt76x8_usb_phy_ids,
  158 + .ops = &mt76x8_usb_phy_ops,
  159 + .probe = mt76x8_usb_phy_probe,
  160 + .priv_auto_alloc_size = sizeof(struct mt76x8_usb_phy),
  161 +};