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 <clk.h> 10#include <dm.h> 11#include <generic-phy.h> 12#include <log.h> 13#include <reset.h> 14#include <asm/io.h> 15#include <linux/bitops.h> 16#include <linux/delay.h> 17 18#define OFS_U2_PHY_AC0 0x800 19#define USBPLL_FBDIV_S 16 20#define USBPLL_FBDIV_M GENMASK(22, 16) 21#define BG_TRIM_S 8 22#define BG_TRIM_M GENMASK(11, 8) 23#define BG_RBSEL_S 6 24#define BG_RBSEL_M GENMASK(7, 6) 25#define BG_RASEL_S 4 26#define BG_RASEL_M GENMASK(5, 4) 27#define BGR_DIV_S 2 28#define BGR_DIV_M GENMASK(3, 2) 29#define CHP_EN BIT(1) 30 31#define OFS_U2_PHY_AC1 0x804 32#define VRT_VREF_SEL_S 28 33#define VRT_VREF_SEL_M GENMASK(30, 28) 34#define TERM_VREF_SEL_S 24 35#define TERM_VREF_SEL_M GENMASK(26, 24) 36#define USBPLL_RSVD BIT(4) 37#define USBPLL_ACCEN BIT(3) 38#define USBPLL_LF BIT(2) 39 40#define OFS_U2_PHY_AC2 0x808 41 42#define OFS_U2_PHY_ACR0 0x810 43#define HSTX_SRCAL_EN BIT(23) 44#define HSTX_SRCTRL_S 16 45#define HSTX_SRCTRL_M GENMASK(18, 16) 46 47#define OFS_U2_PHY_ACR3 0x81C 48#define HSTX_DBIST_S 28 49#define HSTX_DBIST_M GENMASK(31, 28) 50#define HSRX_BIAS_EN_SEL_S 20 51#define HSRX_BIAS_EN_SEL_M GENMASK(21, 20) 52 53#define OFS_U2_PHY_DCR0 0x860 54#define PHYD_RESERVE_S 8 55#define PHYD_RESERVE_M GENMASK(23, 8) 56#define CDR_FILT_S 0 57#define CDR_FILT_M GENMASK(3, 0) 58 59#define OFS_U2_PHY_DTM0 0x868 60#define FORCE_USB_CLKEN BIT(25) 61 62#define OFS_FM_CR0 0xf00 63#define FREQDET_EN BIT(24) 64#define CYCLECNT_S 0 65#define CYCLECNT_M GENMASK(23, 0) 66 67#define OFS_FM_MONR0 0xf0c 68 69#define OFS_FM_MONR1 0xf10 70#define FRCK_EN BIT(8) 71 72#define U2_SR_COEF_7628 32 73 74struct mt76x8_usb_phy { 75 void __iomem *base; 76 struct clk cg; /* for clock gating */ 77 struct reset_ctl rst_phy; 78}; 79 80static void phy_w32(struct mt76x8_usb_phy *phy, u32 reg, u32 val) 81{ 82 writel(val, phy->base + reg); 83} 84 85static u32 phy_r32(struct mt76x8_usb_phy *phy, u32 reg) 86{ 87 return readl(phy->base + reg); 88} 89 90static void phy_rmw32(struct mt76x8_usb_phy *phy, u32 reg, u32 clr, u32 set) 91{ 92 clrsetbits_32(phy->base + reg, clr, set); 93} 94 95static void mt76x8_usb_phy_init(struct mt76x8_usb_phy *phy) 96{ 97 phy_r32(phy, OFS_U2_PHY_AC2); 98 phy_r32(phy, OFS_U2_PHY_ACR0); 99 phy_r32(phy, OFS_U2_PHY_DCR0); 100 101 phy_w32(phy, OFS_U2_PHY_DCR0, 102 (0xffff << PHYD_RESERVE_S) | (2 << CDR_FILT_S)); 103 phy_r32(phy, OFS_U2_PHY_DCR0); 104 105 phy_w32(phy, OFS_U2_PHY_DCR0, 106 (0x5555 << PHYD_RESERVE_S) | (2 << CDR_FILT_S)); 107 phy_r32(phy, OFS_U2_PHY_DCR0); 108 109 phy_w32(phy, OFS_U2_PHY_DCR0, 110 (0xaaaa << PHYD_RESERVE_S) | (2 << CDR_FILT_S)); 111 phy_r32(phy, OFS_U2_PHY_DCR0); 112 113 phy_w32(phy, OFS_U2_PHY_DCR0, 114 (4 << PHYD_RESERVE_S) | (2 << CDR_FILT_S)); 115 phy_r32(phy, OFS_U2_PHY_DCR0); 116 117 phy_w32(phy, OFS_U2_PHY_AC0, 118 (0x48 << USBPLL_FBDIV_S) | (8 << BG_TRIM_S) | 119 (1 << BG_RBSEL_S) | (2 << BG_RASEL_S) | (2 << BGR_DIV_S) | 120 CHP_EN); 121 122 phy_w32(phy, OFS_U2_PHY_AC1, 123 (4 << VRT_VREF_SEL_S) | (4 << TERM_VREF_SEL_S) | USBPLL_RSVD | 124 USBPLL_ACCEN | USBPLL_LF); 125 126 phy_w32(phy, OFS_U2_PHY_ACR3, 127 (12 << HSTX_DBIST_S) | (2 << HSRX_BIAS_EN_SEL_S)); 128 129 phy_w32(phy, OFS_U2_PHY_DTM0, FORCE_USB_CLKEN); 130} 131 132static void mt76x8_usb_phy_sr_calibrate(struct mt76x8_usb_phy *phy) 133{ 134 u32 fmout, tmp = 4; 135 int i; 136 137 /* Enable HS TX SR calibration */ 138 phy_rmw32(phy, OFS_U2_PHY_ACR0, 0, HSTX_SRCAL_EN); 139 mdelay(1); 140 141 /* Enable free run clock */ 142 phy_rmw32(phy, OFS_FM_MONR1, 0, FRCK_EN); 143 144 /* Set cycle count = 0x400 */ 145 phy_rmw32(phy, OFS_FM_CR0, CYCLECNT_M, 0x400 << CYCLECNT_S); 146 147 /* Enable frequency meter */ 148 phy_rmw32(phy, OFS_FM_CR0, 0, FREQDET_EN); 149 150 /* Wait for FM detection done, set timeout to 10ms */ 151 for (i = 0; i < 10; i++) { 152 fmout = phy_r32(phy, OFS_FM_MONR0); 153 154 if (fmout) 155 break; 156 157 mdelay(1); 158 } 159 160 /* Disable frequency meter */ 161 phy_rmw32(phy, OFS_FM_CR0, FREQDET_EN, 0); 162 163 /* Disable free run clock */ 164 phy_rmw32(phy, OFS_FM_MONR1, FRCK_EN, 0); 165 166 /* Disable HS TX SR calibration */ 167 phy_rmw32(phy, OFS_U2_PHY_ACR0, HSTX_SRCAL_EN, 0); 168 mdelay(1); 169 170 if (fmout) { 171 /* 172 * set reg = (1024 / FM_OUT) * 25 * 0.028 173 * (round to the nearest digits) 174 */ 175 tmp = (((1024 * 25 * U2_SR_COEF_7628) / fmout) + 500) / 1000; 176 } 177 178 phy_rmw32(phy, OFS_U2_PHY_ACR0, HSTX_SRCTRL_M, 179 (tmp << HSTX_SRCTRL_S) & HSTX_SRCTRL_M); 180} 181 182static int mt76x8_usb_phy_power_on(struct phy *_phy) 183{ 184 struct mt76x8_usb_phy *phy = dev_get_priv(_phy->dev); 185 186 clk_enable(&phy->cg); 187 188 reset_deassert(&phy->rst_phy); 189 190 /* 191 * The SDK kernel had a delay of 100ms. however on device 192 * testing showed that 10ms is enough 193 */ 194 mdelay(10); 195 196 mt76x8_usb_phy_init(phy); 197 mt76x8_usb_phy_sr_calibrate(phy); 198 199 return 0; 200} 201 202static int mt76x8_usb_phy_power_off(struct phy *_phy) 203{ 204 struct mt76x8_usb_phy *phy = dev_get_priv(_phy->dev); 205 206 clk_disable(&phy->cg); 207 208 reset_assert(&phy->rst_phy); 209 210 return 0; 211} 212 213static int mt76x8_usb_phy_probe(struct udevice *dev) 214{ 215 struct mt76x8_usb_phy *phy = dev_get_priv(dev); 216 int ret; 217 218 phy->base = dev_read_addr_ptr(dev); 219 if (!phy->base) 220 return -EINVAL; 221 222 /* clock gate */ 223 ret = clk_get_by_name(dev, "cg", &phy->cg); 224 if (ret) 225 return ret; 226 227 ret = reset_get_by_name(dev, "phy", &phy->rst_phy); 228 if (ret) 229 return ret; 230 231 return 0; 232} 233 234static struct phy_ops mt76x8_usb_phy_ops = { 235 .power_on = mt76x8_usb_phy_power_on, 236 .power_off = mt76x8_usb_phy_power_off, 237}; 238 239static const struct udevice_id mt76x8_usb_phy_ids[] = { 240 { .compatible = "mediatek,mt7628-usbphy" }, 241 { } 242}; 243 244U_BOOT_DRIVER(mt76x8_usb_phy) = { 245 .name = "mt76x8_usb_phy", 246 .id = UCLASS_PHY, 247 .of_match = mt76x8_usb_phy_ids, 248 .ops = &mt76x8_usb_phy_ops, 249 .probe = mt76x8_usb_phy_probe, 250 .priv_auto = sizeof(struct mt76x8_usb_phy), 251}; 252