diff options
Diffstat (limited to 'drivers/phy')
-rw-r--r-- | drivers/phy/Kconfig | 8 | ||||
-rw-r--r-- | drivers/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/phy/mt76x8-usb-phy.c | 161 | ||||
-rw-r--r-- | drivers/phy/phy-stm32-usbphyc.c | 111 |
4 files changed, 228 insertions, 53 deletions
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 <sr@denx.de> + * + * Derived from linux/drivers/phy/ralink/phy-ralink-usb.c + * Copyright (C) 2017 John Crispin <john@phrozen.org> + */ + +#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), +}; diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index 8e98b4b627..6f1119036d 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -37,7 +37,8 @@ #define MAX_PHYS 2 -#define PLL_LOCK_TIME_US 100 +/* max 100 us for PLL lock and 100 us for PHY init */ +#define PLL_INIT_TIME_US 200 #define PLL_PWR_DOWN_TIME_US 5 #define PLL_FVCO 2880 /* in MHz */ #define PLL_INFF_MIN_RATE 19200000 /* in Hz */ @@ -51,17 +52,17 @@ struct pll_params { struct stm32_usbphyc { fdt_addr_t base; struct clk clk; + struct udevice *vdda1v1; + struct udevice *vdda1v8; struct stm32_usbphyc_phy { struct udevice *vdd; - struct udevice *vdda1v1; - struct udevice *vdda1v8; - int index; bool init; bool powered; } phys[MAX_PHYS]; }; -void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params) +static void stm32_usbphyc_get_pll_params(u32 clk_rate, + struct pll_params *pll_params) { unsigned long long fvco, ndiv, frac; @@ -154,6 +155,18 @@ static int stm32_usbphyc_phy_init(struct phy *phy) if (pllen && stm32_usbphyc_is_init(usbphyc)) goto initialized; + if (usbphyc->vdda1v1) { + ret = regulator_set_enable(usbphyc->vdda1v1, true); + if (ret) + return ret; + } + + if (usbphyc->vdda1v8) { + ret = regulator_set_enable(usbphyc->vdda1v8, true); + if (ret) + return ret; + } + if (pllen) { clrbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); udelay(PLL_PWR_DOWN_TIME_US); @@ -165,11 +178,8 @@ static int stm32_usbphyc_phy_init(struct phy *phy) setbits_le32(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); - /* - * We must wait PLL_LOCK_TIME_US before checking that PLLEN - * bit is still set - */ - udelay(PLL_LOCK_TIME_US); + /* We must wait PLL_INIT_TIME_US before using PHY */ + udelay(PLL_INIT_TIME_US); if (!(readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN)) return -EIO; @@ -184,6 +194,7 @@ static int stm32_usbphyc_phy_exit(struct phy *phy) { struct stm32_usbphyc *usbphyc = dev_get_priv(phy->dev); struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + phy->id; + int ret; pr_debug("%s phy ID = %lu\n", __func__, phy->id); usbphyc_phy->init = false; @@ -203,6 +214,18 @@ static int stm32_usbphyc_phy_exit(struct phy *phy) if (readl(usbphyc->base + STM32_USBPHYC_PLL) & PLLEN) return -EIO; + if (usbphyc->vdda1v1) { + ret = regulator_set_enable(usbphyc->vdda1v1, false); + if (ret) + return ret; + } + + if (usbphyc->vdda1v8) { + ret = regulator_set_enable(usbphyc->vdda1v8, false); + if (ret) + return ret; + } + return 0; } @@ -213,17 +236,6 @@ static int stm32_usbphyc_phy_power_on(struct phy *phy) int ret; pr_debug("%s phy ID = %lu\n", __func__, phy->id); - if (usbphyc_phy->vdda1v1) { - ret = regulator_set_enable(usbphyc_phy->vdda1v1, true); - if (ret) - return ret; - } - - if (usbphyc_phy->vdda1v8) { - ret = regulator_set_enable(usbphyc_phy->vdda1v8, true); - if (ret) - return ret; - } if (usbphyc_phy->vdd) { ret = regulator_set_enable(usbphyc_phy->vdd, true); if (ret) @@ -247,18 +259,6 @@ static int stm32_usbphyc_phy_power_off(struct phy *phy) if (stm32_usbphyc_is_powered(usbphyc)) return 0; - if (usbphyc_phy->vdda1v1) { - ret = regulator_set_enable(usbphyc_phy->vdda1v1, false); - if (ret) - return ret; - } - - if (usbphyc_phy->vdda1v8) { - ret = regulator_set_enable(usbphyc_phy->vdda1v8, false); - if (ret) - return ret; - } - if (usbphyc_phy->vdd) { ret = regulator_set_enable(usbphyc_phy->vdd, false); if (ret) @@ -298,19 +298,20 @@ static int stm32_usbphyc_get_regulator(struct udevice *dev, ofnode node, static int stm32_usbphyc_of_xlate(struct phy *phy, struct ofnode_phandle_args *args) { - if (args->args_count > 1) { - pr_debug("%s: invalid args_count: %d\n", __func__, - args->args_count); - return -EINVAL; - } + if (args->args_count < 1) + return -ENODEV; if (args->args[0] >= MAX_PHYS) return -ENODEV; - if (args->args_count) - phy->id = args->args[0]; - else - phy->id = 0; + phy->id = args->args[0]; + + if ((phy->id == 0 && args->args_count != 1) || + (phy->id == 1 && args->args_count != 2)) { + dev_err(dev, "invalid number of cells for phy port%ld\n", + phy->id); + return -EINVAL; + } return 0; } @@ -351,6 +352,21 @@ static int stm32_usbphyc_probe(struct udevice *dev) reset_deassert(&reset); } + /* get usbphyc regulator */ + ret = device_get_supply_regulator(dev, "vdda1v1-supply", + &usbphyc->vdda1v1); + if (ret) { + dev_err(dev, "Can't get vdda1v1-supply regulator\n"); + return ret; + } + + ret = device_get_supply_regulator(dev, "vdda1v8-supply", + &usbphyc->vdda1v8); + if (ret) { + dev_err(dev, "Can't get vdda1v8-supply regulator\n"); + return ret; + } + /* * parse all PHY subnodes in order to populate regulator associated * to each PHY port @@ -359,7 +375,6 @@ static int stm32_usbphyc_probe(struct udevice *dev) for (i = 0; i < MAX_PHYS; i++) { struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + i; - usbphyc_phy->index = i; usbphyc_phy->init = false; usbphyc_phy->powered = false; ret = stm32_usbphyc_get_regulator(dev, node, "phy-supply", @@ -367,16 +382,6 @@ static int stm32_usbphyc_probe(struct udevice *dev) if (ret) return ret; - ret = stm32_usbphyc_get_regulator(dev, node, "vdda1v1-supply", - &usbphyc_phy->vdda1v1); - if (ret) - return ret; - - ret = stm32_usbphyc_get_regulator(dev, node, "vdda1v8-supply", - &usbphyc_phy->vdda1v8); - if (ret) - return ret; - node = dev_read_next_subnode(node); } |