1c1eb8f83SChunfeng Yun // SPDX-License-Identifier: GPL-2.0 2c1eb8f83SChunfeng Yun /* 3c1eb8f83SChunfeng Yun * MediaTek USB3.1 gen2 xsphy Driver 4c1eb8f83SChunfeng Yun * 5c1eb8f83SChunfeng Yun * Copyright (c) 2018 MediaTek Inc. 6c1eb8f83SChunfeng Yun * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> 7c1eb8f83SChunfeng Yun * 8c1eb8f83SChunfeng Yun */ 9c1eb8f83SChunfeng Yun 10c1eb8f83SChunfeng Yun #include <dt-bindings/phy/phy.h> 11c1eb8f83SChunfeng Yun #include <linux/clk.h> 12c1eb8f83SChunfeng Yun #include <linux/delay.h> 13c1eb8f83SChunfeng Yun #include <linux/iopoll.h> 14c1eb8f83SChunfeng Yun #include <linux/module.h> 15c1eb8f83SChunfeng Yun #include <linux/of_address.h> 16c1eb8f83SChunfeng Yun #include <linux/phy/phy.h> 17c1eb8f83SChunfeng Yun #include <linux/platform_device.h> 18c1eb8f83SChunfeng Yun 19*9520bbf3SChunfeng Yun #include "phy-mtk-io.h" 20*9520bbf3SChunfeng Yun 21c1eb8f83SChunfeng Yun /* u2 phy banks */ 22c1eb8f83SChunfeng Yun #define SSUSB_SIFSLV_MISC 0x000 23c1eb8f83SChunfeng Yun #define SSUSB_SIFSLV_U2FREQ 0x100 24c1eb8f83SChunfeng Yun #define SSUSB_SIFSLV_U2PHY_COM 0x300 25c1eb8f83SChunfeng Yun 26c1eb8f83SChunfeng Yun /* u3 phy shared banks */ 27c1eb8f83SChunfeng Yun #define SSPXTP_SIFSLV_DIG_GLB 0x000 28c1eb8f83SChunfeng Yun #define SSPXTP_SIFSLV_PHYA_GLB 0x100 29c1eb8f83SChunfeng Yun 30c1eb8f83SChunfeng Yun /* u3 phy banks */ 31c1eb8f83SChunfeng Yun #define SSPXTP_SIFSLV_DIG_LN_TOP 0x000 32c1eb8f83SChunfeng Yun #define SSPXTP_SIFSLV_DIG_LN_TX0 0x100 33c1eb8f83SChunfeng Yun #define SSPXTP_SIFSLV_DIG_LN_RX0 0x200 34c1eb8f83SChunfeng Yun #define SSPXTP_SIFSLV_DIG_LN_DAIF 0x300 35c1eb8f83SChunfeng Yun #define SSPXTP_SIFSLV_PHYA_LN 0x400 36c1eb8f83SChunfeng Yun 37c1eb8f83SChunfeng Yun #define XSP_U2FREQ_FMCR0 ((SSUSB_SIFSLV_U2FREQ) + 0x00) 38c1eb8f83SChunfeng Yun #define P2F_RG_FREQDET_EN BIT(24) 39c1eb8f83SChunfeng Yun #define P2F_RG_CYCLECNT GENMASK(23, 0) 40c1eb8f83SChunfeng Yun #define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x)) 41c1eb8f83SChunfeng Yun 42c1eb8f83SChunfeng Yun #define XSP_U2FREQ_MMONR0 ((SSUSB_SIFSLV_U2FREQ) + 0x0c) 43c1eb8f83SChunfeng Yun 44c1eb8f83SChunfeng Yun #define XSP_U2FREQ_FMMONR1 ((SSUSB_SIFSLV_U2FREQ) + 0x10) 45c1eb8f83SChunfeng Yun #define P2F_RG_FRCK_EN BIT(8) 46c1eb8f83SChunfeng Yun #define P2F_USB_FM_VALID BIT(0) 47c1eb8f83SChunfeng Yun 48c1eb8f83SChunfeng Yun #define XSP_USBPHYACR0 ((SSUSB_SIFSLV_U2PHY_COM) + 0x00) 49c1eb8f83SChunfeng Yun #define P2A0_RG_INTR_EN BIT(5) 50c1eb8f83SChunfeng Yun 51c1eb8f83SChunfeng Yun #define XSP_USBPHYACR1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x04) 52c1eb8f83SChunfeng Yun #define P2A1_RG_INTR_CAL GENMASK(23, 19) 53c1eb8f83SChunfeng Yun #define P2A1_RG_INTR_CAL_VAL(x) ((0x1f & (x)) << 19) 54c1eb8f83SChunfeng Yun #define P2A1_RG_VRT_SEL GENMASK(14, 12) 55c1eb8f83SChunfeng Yun #define P2A1_RG_VRT_SEL_VAL(x) ((0x7 & (x)) << 12) 56c1eb8f83SChunfeng Yun #define P2A1_RG_TERM_SEL GENMASK(10, 8) 57c1eb8f83SChunfeng Yun #define P2A1_RG_TERM_SEL_VAL(x) ((0x7 & (x)) << 8) 58c1eb8f83SChunfeng Yun 59c1eb8f83SChunfeng Yun #define XSP_USBPHYACR5 ((SSUSB_SIFSLV_U2PHY_COM) + 0x014) 60c1eb8f83SChunfeng Yun #define P2A5_RG_HSTX_SRCAL_EN BIT(15) 61c1eb8f83SChunfeng Yun #define P2A5_RG_HSTX_SRCTRL GENMASK(14, 12) 62c1eb8f83SChunfeng Yun #define P2A5_RG_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12) 63c1eb8f83SChunfeng Yun 64c1eb8f83SChunfeng Yun #define XSP_USBPHYACR6 ((SSUSB_SIFSLV_U2PHY_COM) + 0x018) 65c1eb8f83SChunfeng Yun #define P2A6_RG_BC11_SW_EN BIT(23) 66c1eb8f83SChunfeng Yun #define P2A6_RG_OTG_VBUSCMP_EN BIT(20) 67c1eb8f83SChunfeng Yun 68c1eb8f83SChunfeng Yun #define XSP_U2PHYDTM1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x06C) 69c1eb8f83SChunfeng Yun #define P2D_FORCE_IDDIG BIT(9) 70c1eb8f83SChunfeng Yun #define P2D_RG_VBUSVALID BIT(5) 71c1eb8f83SChunfeng Yun #define P2D_RG_SESSEND BIT(4) 72c1eb8f83SChunfeng Yun #define P2D_RG_AVALID BIT(2) 73c1eb8f83SChunfeng Yun #define P2D_RG_IDDIG BIT(1) 74c1eb8f83SChunfeng Yun 75c1eb8f83SChunfeng Yun #define SSPXTP_PHYA_GLB_00 ((SSPXTP_SIFSLV_PHYA_GLB) + 0x00) 76c1eb8f83SChunfeng Yun #define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(21, 16) 77c1eb8f83SChunfeng Yun #define RG_XTP_GLB_BIAS_INTR_CTRL_VAL(x) ((0x3f & (x)) << 16) 78c1eb8f83SChunfeng Yun 79c1eb8f83SChunfeng Yun #define SSPXTP_PHYA_LN_04 ((SSPXTP_SIFSLV_PHYA_LN) + 0x04) 80c1eb8f83SChunfeng Yun #define RG_XTP_LN0_TX_IMPSEL GENMASK(4, 0) 81c1eb8f83SChunfeng Yun #define RG_XTP_LN0_TX_IMPSEL_VAL(x) (0x1f & (x)) 82c1eb8f83SChunfeng Yun 83c1eb8f83SChunfeng Yun #define SSPXTP_PHYA_LN_14 ((SSPXTP_SIFSLV_PHYA_LN) + 0x014) 84c1eb8f83SChunfeng Yun #define RG_XTP_LN0_RX_IMPSEL GENMASK(4, 0) 85c1eb8f83SChunfeng Yun #define RG_XTP_LN0_RX_IMPSEL_VAL(x) (0x1f & (x)) 86c1eb8f83SChunfeng Yun 87c1eb8f83SChunfeng Yun #define XSP_REF_CLK 26 /* MHZ */ 88c1eb8f83SChunfeng Yun #define XSP_SLEW_RATE_COEF 17 89c1eb8f83SChunfeng Yun #define XSP_SR_COEF_DIVISOR 1000 90c1eb8f83SChunfeng Yun #define XSP_FM_DET_CYCLE_CNT 1024 91c1eb8f83SChunfeng Yun 92c1eb8f83SChunfeng Yun struct xsphy_instance { 93c1eb8f83SChunfeng Yun struct phy *phy; 94c1eb8f83SChunfeng Yun void __iomem *port_base; 95c1eb8f83SChunfeng Yun struct clk *ref_clk; /* reference clock of anolog phy */ 96c1eb8f83SChunfeng Yun u32 index; 97c1eb8f83SChunfeng Yun u32 type; 98c1eb8f83SChunfeng Yun /* only for HQA test */ 99c1eb8f83SChunfeng Yun int efuse_intr; 100c1eb8f83SChunfeng Yun int efuse_tx_imp; 101c1eb8f83SChunfeng Yun int efuse_rx_imp; 102c1eb8f83SChunfeng Yun /* u2 eye diagram */ 103c1eb8f83SChunfeng Yun int eye_src; 104c1eb8f83SChunfeng Yun int eye_vrt; 105c1eb8f83SChunfeng Yun int eye_term; 106c1eb8f83SChunfeng Yun }; 107c1eb8f83SChunfeng Yun 108c1eb8f83SChunfeng Yun struct mtk_xsphy { 109c1eb8f83SChunfeng Yun struct device *dev; 110c1eb8f83SChunfeng Yun void __iomem *glb_base; /* only shared u3 sif */ 111c1eb8f83SChunfeng Yun struct xsphy_instance **phys; 112c1eb8f83SChunfeng Yun int nphys; 113c1eb8f83SChunfeng Yun int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */ 114c1eb8f83SChunfeng Yun int src_coef; /* coefficient for slew rate calibrate */ 115c1eb8f83SChunfeng Yun }; 116c1eb8f83SChunfeng Yun 117c1eb8f83SChunfeng Yun static void u2_phy_slew_rate_calibrate(struct mtk_xsphy *xsphy, 118c1eb8f83SChunfeng Yun struct xsphy_instance *inst) 119c1eb8f83SChunfeng Yun { 120c1eb8f83SChunfeng Yun void __iomem *pbase = inst->port_base; 121c1eb8f83SChunfeng Yun int calib_val; 122c1eb8f83SChunfeng Yun int fm_out; 123c1eb8f83SChunfeng Yun u32 tmp; 124c1eb8f83SChunfeng Yun 125c1eb8f83SChunfeng Yun /* use force value */ 126c1eb8f83SChunfeng Yun if (inst->eye_src) 127c1eb8f83SChunfeng Yun return; 128c1eb8f83SChunfeng Yun 129c1eb8f83SChunfeng Yun /* enable USB ring oscillator */ 130*9520bbf3SChunfeng Yun mtk_phy_set_bits(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN); 131c1eb8f83SChunfeng Yun udelay(1); /* wait clock stable */ 132c1eb8f83SChunfeng Yun 133c1eb8f83SChunfeng Yun /* enable free run clock */ 134*9520bbf3SChunfeng Yun mtk_phy_set_bits(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN); 135c1eb8f83SChunfeng Yun 136c1eb8f83SChunfeng Yun /* set cycle count as 1024 */ 137*9520bbf3SChunfeng Yun mtk_phy_update_bits(pbase + XSP_U2FREQ_FMCR0, P2F_RG_CYCLECNT, 138*9520bbf3SChunfeng Yun P2F_RG_CYCLECNT_VAL(XSP_FM_DET_CYCLE_CNT)); 139c1eb8f83SChunfeng Yun 140c1eb8f83SChunfeng Yun /* enable frequency meter */ 141*9520bbf3SChunfeng Yun mtk_phy_set_bits(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN); 142c1eb8f83SChunfeng Yun 143c1eb8f83SChunfeng Yun /* ignore return value */ 144c1eb8f83SChunfeng Yun readl_poll_timeout(pbase + XSP_U2FREQ_FMMONR1, tmp, 145c1eb8f83SChunfeng Yun (tmp & P2F_USB_FM_VALID), 10, 200); 146c1eb8f83SChunfeng Yun 147c1eb8f83SChunfeng Yun fm_out = readl(pbase + XSP_U2FREQ_MMONR0); 148c1eb8f83SChunfeng Yun 149c1eb8f83SChunfeng Yun /* disable frequency meter */ 150*9520bbf3SChunfeng Yun mtk_phy_clear_bits(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN); 151c1eb8f83SChunfeng Yun 152c1eb8f83SChunfeng Yun /* disable free run clock */ 153*9520bbf3SChunfeng Yun mtk_phy_clear_bits(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN); 154c1eb8f83SChunfeng Yun 155c1eb8f83SChunfeng Yun if (fm_out) { 156c1eb8f83SChunfeng Yun /* (1024 / FM_OUT) x reference clock frequency x coefficient */ 157c1eb8f83SChunfeng Yun tmp = xsphy->src_ref_clk * xsphy->src_coef; 158c1eb8f83SChunfeng Yun tmp = (tmp * XSP_FM_DET_CYCLE_CNT) / fm_out; 159c1eb8f83SChunfeng Yun calib_val = DIV_ROUND_CLOSEST(tmp, XSP_SR_COEF_DIVISOR); 160c1eb8f83SChunfeng Yun } else { 161c1eb8f83SChunfeng Yun /* if FM detection fail, set default value */ 162c1eb8f83SChunfeng Yun calib_val = 3; 163c1eb8f83SChunfeng Yun } 164c1eb8f83SChunfeng Yun dev_dbg(xsphy->dev, "phy.%d, fm_out:%d, calib:%d (clk:%d, coef:%d)\n", 165c1eb8f83SChunfeng Yun inst->index, fm_out, calib_val, 166c1eb8f83SChunfeng Yun xsphy->src_ref_clk, xsphy->src_coef); 167c1eb8f83SChunfeng Yun 168c1eb8f83SChunfeng Yun /* set HS slew rate */ 169*9520bbf3SChunfeng Yun mtk_phy_update_bits(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL, 170*9520bbf3SChunfeng Yun P2A5_RG_HSTX_SRCTRL_VAL(calib_val)); 171c1eb8f83SChunfeng Yun 172c1eb8f83SChunfeng Yun /* disable USB ring oscillator */ 173*9520bbf3SChunfeng Yun mtk_phy_clear_bits(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN); 174c1eb8f83SChunfeng Yun } 175c1eb8f83SChunfeng Yun 176c1eb8f83SChunfeng Yun static void u2_phy_instance_init(struct mtk_xsphy *xsphy, 177c1eb8f83SChunfeng Yun struct xsphy_instance *inst) 178c1eb8f83SChunfeng Yun { 179c1eb8f83SChunfeng Yun void __iomem *pbase = inst->port_base; 180c1eb8f83SChunfeng Yun 181c1eb8f83SChunfeng Yun /* DP/DM BC1.1 path Disable */ 182*9520bbf3SChunfeng Yun mtk_phy_clear_bits(pbase + XSP_USBPHYACR6, P2A6_RG_BC11_SW_EN); 183c1eb8f83SChunfeng Yun 184*9520bbf3SChunfeng Yun mtk_phy_set_bits(pbase + XSP_USBPHYACR0, P2A0_RG_INTR_EN); 185c1eb8f83SChunfeng Yun } 186c1eb8f83SChunfeng Yun 187c1eb8f83SChunfeng Yun static void u2_phy_instance_power_on(struct mtk_xsphy *xsphy, 188c1eb8f83SChunfeng Yun struct xsphy_instance *inst) 189c1eb8f83SChunfeng Yun { 190c1eb8f83SChunfeng Yun void __iomem *pbase = inst->port_base; 191c1eb8f83SChunfeng Yun u32 index = inst->index; 192c1eb8f83SChunfeng Yun 193*9520bbf3SChunfeng Yun mtk_phy_set_bits(pbase + XSP_USBPHYACR6, P2A6_RG_OTG_VBUSCMP_EN); 194c1eb8f83SChunfeng Yun 195*9520bbf3SChunfeng Yun mtk_phy_update_bits(pbase + XSP_U2PHYDTM1, 196*9520bbf3SChunfeng Yun P2D_RG_VBUSVALID | P2D_RG_AVALID | P2D_RG_SESSEND, 197*9520bbf3SChunfeng Yun P2D_RG_VBUSVALID | P2D_RG_AVALID); 198c1eb8f83SChunfeng Yun 199c1eb8f83SChunfeng Yun dev_dbg(xsphy->dev, "%s(%d)\n", __func__, index); 200c1eb8f83SChunfeng Yun } 201c1eb8f83SChunfeng Yun 202c1eb8f83SChunfeng Yun static void u2_phy_instance_power_off(struct mtk_xsphy *xsphy, 203c1eb8f83SChunfeng Yun struct xsphy_instance *inst) 204c1eb8f83SChunfeng Yun { 205c1eb8f83SChunfeng Yun void __iomem *pbase = inst->port_base; 206c1eb8f83SChunfeng Yun u32 index = inst->index; 207c1eb8f83SChunfeng Yun 208*9520bbf3SChunfeng Yun mtk_phy_clear_bits(pbase + XSP_USBPHYACR6, P2A6_RG_OTG_VBUSCMP_EN); 209c1eb8f83SChunfeng Yun 210*9520bbf3SChunfeng Yun mtk_phy_update_bits(pbase + XSP_U2PHYDTM1, 211*9520bbf3SChunfeng Yun P2D_RG_VBUSVALID | P2D_RG_AVALID | P2D_RG_SESSEND, 212*9520bbf3SChunfeng Yun P2D_RG_SESSEND); 213c1eb8f83SChunfeng Yun 214c1eb8f83SChunfeng Yun dev_dbg(xsphy->dev, "%s(%d)\n", __func__, index); 215c1eb8f83SChunfeng Yun } 216c1eb8f83SChunfeng Yun 217c1eb8f83SChunfeng Yun static void u2_phy_instance_set_mode(struct mtk_xsphy *xsphy, 218c1eb8f83SChunfeng Yun struct xsphy_instance *inst, 219c1eb8f83SChunfeng Yun enum phy_mode mode) 220c1eb8f83SChunfeng Yun { 221c1eb8f83SChunfeng Yun u32 tmp; 222c1eb8f83SChunfeng Yun 223c1eb8f83SChunfeng Yun tmp = readl(inst->port_base + XSP_U2PHYDTM1); 224c1eb8f83SChunfeng Yun switch (mode) { 225c1eb8f83SChunfeng Yun case PHY_MODE_USB_DEVICE: 226c1eb8f83SChunfeng Yun tmp |= P2D_FORCE_IDDIG | P2D_RG_IDDIG; 227c1eb8f83SChunfeng Yun break; 228c1eb8f83SChunfeng Yun case PHY_MODE_USB_HOST: 229c1eb8f83SChunfeng Yun tmp |= P2D_FORCE_IDDIG; 230c1eb8f83SChunfeng Yun tmp &= ~P2D_RG_IDDIG; 231c1eb8f83SChunfeng Yun break; 232c1eb8f83SChunfeng Yun case PHY_MODE_USB_OTG: 233c1eb8f83SChunfeng Yun tmp &= ~(P2D_FORCE_IDDIG | P2D_RG_IDDIG); 234c1eb8f83SChunfeng Yun break; 235c1eb8f83SChunfeng Yun default: 236c1eb8f83SChunfeng Yun return; 237c1eb8f83SChunfeng Yun } 238c1eb8f83SChunfeng Yun writel(tmp, inst->port_base + XSP_U2PHYDTM1); 239c1eb8f83SChunfeng Yun } 240c1eb8f83SChunfeng Yun 241c1eb8f83SChunfeng Yun static void phy_parse_property(struct mtk_xsphy *xsphy, 242c1eb8f83SChunfeng Yun struct xsphy_instance *inst) 243c1eb8f83SChunfeng Yun { 244c1eb8f83SChunfeng Yun struct device *dev = &inst->phy->dev; 245c1eb8f83SChunfeng Yun 246c1eb8f83SChunfeng Yun switch (inst->type) { 247c1eb8f83SChunfeng Yun case PHY_TYPE_USB2: 248c1eb8f83SChunfeng Yun device_property_read_u32(dev, "mediatek,efuse-intr", 249c1eb8f83SChunfeng Yun &inst->efuse_intr); 250c1eb8f83SChunfeng Yun device_property_read_u32(dev, "mediatek,eye-src", 251c1eb8f83SChunfeng Yun &inst->eye_src); 252c1eb8f83SChunfeng Yun device_property_read_u32(dev, "mediatek,eye-vrt", 253c1eb8f83SChunfeng Yun &inst->eye_vrt); 254c1eb8f83SChunfeng Yun device_property_read_u32(dev, "mediatek,eye-term", 255c1eb8f83SChunfeng Yun &inst->eye_term); 256c1eb8f83SChunfeng Yun dev_dbg(dev, "intr:%d, src:%d, vrt:%d, term:%d\n", 257c1eb8f83SChunfeng Yun inst->efuse_intr, inst->eye_src, 258c1eb8f83SChunfeng Yun inst->eye_vrt, inst->eye_term); 259c1eb8f83SChunfeng Yun break; 260c1eb8f83SChunfeng Yun case PHY_TYPE_USB3: 261c1eb8f83SChunfeng Yun device_property_read_u32(dev, "mediatek,efuse-intr", 262c1eb8f83SChunfeng Yun &inst->efuse_intr); 263c1eb8f83SChunfeng Yun device_property_read_u32(dev, "mediatek,efuse-tx-imp", 264c1eb8f83SChunfeng Yun &inst->efuse_tx_imp); 265c1eb8f83SChunfeng Yun device_property_read_u32(dev, "mediatek,efuse-rx-imp", 266c1eb8f83SChunfeng Yun &inst->efuse_rx_imp); 267c1eb8f83SChunfeng Yun dev_dbg(dev, "intr:%d, tx-imp:%d, rx-imp:%d\n", 268c1eb8f83SChunfeng Yun inst->efuse_intr, inst->efuse_tx_imp, 269c1eb8f83SChunfeng Yun inst->efuse_rx_imp); 270c1eb8f83SChunfeng Yun break; 271c1eb8f83SChunfeng Yun default: 272c1eb8f83SChunfeng Yun dev_err(xsphy->dev, "incompatible phy type\n"); 273c1eb8f83SChunfeng Yun return; 274c1eb8f83SChunfeng Yun } 275c1eb8f83SChunfeng Yun } 276c1eb8f83SChunfeng Yun 277c1eb8f83SChunfeng Yun static void u2_phy_props_set(struct mtk_xsphy *xsphy, 278c1eb8f83SChunfeng Yun struct xsphy_instance *inst) 279c1eb8f83SChunfeng Yun { 280c1eb8f83SChunfeng Yun void __iomem *pbase = inst->port_base; 281c1eb8f83SChunfeng Yun 282*9520bbf3SChunfeng Yun if (inst->efuse_intr) 283*9520bbf3SChunfeng Yun mtk_phy_update_bits(pbase + XSP_USBPHYACR1, P2A1_RG_INTR_CAL, 284*9520bbf3SChunfeng Yun P2A1_RG_INTR_CAL_VAL(inst->efuse_intr)); 285c1eb8f83SChunfeng Yun 286*9520bbf3SChunfeng Yun if (inst->eye_src) 287*9520bbf3SChunfeng Yun mtk_phy_update_bits(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL, 288*9520bbf3SChunfeng Yun P2A5_RG_HSTX_SRCTRL_VAL(inst->eye_src)); 289c1eb8f83SChunfeng Yun 290*9520bbf3SChunfeng Yun if (inst->eye_vrt) 291*9520bbf3SChunfeng Yun mtk_phy_update_bits(pbase + XSP_USBPHYACR1, P2A1_RG_VRT_SEL, 292*9520bbf3SChunfeng Yun P2A1_RG_VRT_SEL_VAL(inst->eye_vrt)); 293c1eb8f83SChunfeng Yun 294*9520bbf3SChunfeng Yun if (inst->eye_term) 295*9520bbf3SChunfeng Yun mtk_phy_update_bits(pbase + XSP_USBPHYACR1, P2A1_RG_TERM_SEL, 296*9520bbf3SChunfeng Yun P2A1_RG_TERM_SEL_VAL(inst->eye_term)); 297c1eb8f83SChunfeng Yun } 298c1eb8f83SChunfeng Yun 299c1eb8f83SChunfeng Yun static void u3_phy_props_set(struct mtk_xsphy *xsphy, 300c1eb8f83SChunfeng Yun struct xsphy_instance *inst) 301c1eb8f83SChunfeng Yun { 302c1eb8f83SChunfeng Yun void __iomem *pbase = inst->port_base; 303c1eb8f83SChunfeng Yun 304*9520bbf3SChunfeng Yun if (inst->efuse_intr) 305*9520bbf3SChunfeng Yun mtk_phy_update_bits(xsphy->glb_base + SSPXTP_PHYA_GLB_00, 306*9520bbf3SChunfeng Yun RG_XTP_GLB_BIAS_INTR_CTRL, 307*9520bbf3SChunfeng Yun RG_XTP_GLB_BIAS_INTR_CTRL_VAL(inst->efuse_intr)); 308c1eb8f83SChunfeng Yun 309*9520bbf3SChunfeng Yun if (inst->efuse_tx_imp) 310*9520bbf3SChunfeng Yun mtk_phy_update_bits(pbase + SSPXTP_PHYA_LN_04, 311*9520bbf3SChunfeng Yun RG_XTP_LN0_TX_IMPSEL, 312*9520bbf3SChunfeng Yun RG_XTP_LN0_TX_IMPSEL_VAL(inst->efuse_tx_imp)); 313c1eb8f83SChunfeng Yun 314*9520bbf3SChunfeng Yun if (inst->efuse_rx_imp) 315*9520bbf3SChunfeng Yun mtk_phy_update_bits(pbase + SSPXTP_PHYA_LN_14, 316*9520bbf3SChunfeng Yun RG_XTP_LN0_RX_IMPSEL, 317*9520bbf3SChunfeng Yun RG_XTP_LN0_RX_IMPSEL_VAL(inst->efuse_rx_imp)); 318c1eb8f83SChunfeng Yun } 319c1eb8f83SChunfeng Yun 320c1eb8f83SChunfeng Yun static int mtk_phy_init(struct phy *phy) 321c1eb8f83SChunfeng Yun { 322c1eb8f83SChunfeng Yun struct xsphy_instance *inst = phy_get_drvdata(phy); 323c1eb8f83SChunfeng Yun struct mtk_xsphy *xsphy = dev_get_drvdata(phy->dev.parent); 324c1eb8f83SChunfeng Yun int ret; 325c1eb8f83SChunfeng Yun 326c1eb8f83SChunfeng Yun ret = clk_prepare_enable(inst->ref_clk); 327c1eb8f83SChunfeng Yun if (ret) { 328c1eb8f83SChunfeng Yun dev_err(xsphy->dev, "failed to enable ref_clk\n"); 329c1eb8f83SChunfeng Yun return ret; 330c1eb8f83SChunfeng Yun } 331c1eb8f83SChunfeng Yun 332c1eb8f83SChunfeng Yun switch (inst->type) { 333c1eb8f83SChunfeng Yun case PHY_TYPE_USB2: 334c1eb8f83SChunfeng Yun u2_phy_instance_init(xsphy, inst); 335c1eb8f83SChunfeng Yun u2_phy_props_set(xsphy, inst); 336c1eb8f83SChunfeng Yun break; 337c1eb8f83SChunfeng Yun case PHY_TYPE_USB3: 338c1eb8f83SChunfeng Yun u3_phy_props_set(xsphy, inst); 339c1eb8f83SChunfeng Yun break; 340c1eb8f83SChunfeng Yun default: 341c1eb8f83SChunfeng Yun dev_err(xsphy->dev, "incompatible phy type\n"); 342c1eb8f83SChunfeng Yun clk_disable_unprepare(inst->ref_clk); 343c1eb8f83SChunfeng Yun return -EINVAL; 344c1eb8f83SChunfeng Yun } 345c1eb8f83SChunfeng Yun 346c1eb8f83SChunfeng Yun return 0; 347c1eb8f83SChunfeng Yun } 348c1eb8f83SChunfeng Yun 349c1eb8f83SChunfeng Yun static int mtk_phy_power_on(struct phy *phy) 350c1eb8f83SChunfeng Yun { 351c1eb8f83SChunfeng Yun struct xsphy_instance *inst = phy_get_drvdata(phy); 352c1eb8f83SChunfeng Yun struct mtk_xsphy *xsphy = dev_get_drvdata(phy->dev.parent); 353c1eb8f83SChunfeng Yun 354c1eb8f83SChunfeng Yun if (inst->type == PHY_TYPE_USB2) { 355c1eb8f83SChunfeng Yun u2_phy_instance_power_on(xsphy, inst); 356c1eb8f83SChunfeng Yun u2_phy_slew_rate_calibrate(xsphy, inst); 357c1eb8f83SChunfeng Yun } 358c1eb8f83SChunfeng Yun 359c1eb8f83SChunfeng Yun return 0; 360c1eb8f83SChunfeng Yun } 361c1eb8f83SChunfeng Yun 362c1eb8f83SChunfeng Yun static int mtk_phy_power_off(struct phy *phy) 363c1eb8f83SChunfeng Yun { 364c1eb8f83SChunfeng Yun struct xsphy_instance *inst = phy_get_drvdata(phy); 365c1eb8f83SChunfeng Yun struct mtk_xsphy *xsphy = dev_get_drvdata(phy->dev.parent); 366c1eb8f83SChunfeng Yun 367c1eb8f83SChunfeng Yun if (inst->type == PHY_TYPE_USB2) 368c1eb8f83SChunfeng Yun u2_phy_instance_power_off(xsphy, inst); 369c1eb8f83SChunfeng Yun 370c1eb8f83SChunfeng Yun return 0; 371c1eb8f83SChunfeng Yun } 372c1eb8f83SChunfeng Yun 373c1eb8f83SChunfeng Yun static int mtk_phy_exit(struct phy *phy) 374c1eb8f83SChunfeng Yun { 375c1eb8f83SChunfeng Yun struct xsphy_instance *inst = phy_get_drvdata(phy); 376c1eb8f83SChunfeng Yun 377c1eb8f83SChunfeng Yun clk_disable_unprepare(inst->ref_clk); 378c1eb8f83SChunfeng Yun return 0; 379c1eb8f83SChunfeng Yun } 380c1eb8f83SChunfeng Yun 38179a5a18aSGrygorii Strashko static int mtk_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) 382c1eb8f83SChunfeng Yun { 383c1eb8f83SChunfeng Yun struct xsphy_instance *inst = phy_get_drvdata(phy); 384c1eb8f83SChunfeng Yun struct mtk_xsphy *xsphy = dev_get_drvdata(phy->dev.parent); 385c1eb8f83SChunfeng Yun 386c1eb8f83SChunfeng Yun if (inst->type == PHY_TYPE_USB2) 387c1eb8f83SChunfeng Yun u2_phy_instance_set_mode(xsphy, inst, mode); 388c1eb8f83SChunfeng Yun 389c1eb8f83SChunfeng Yun return 0; 390c1eb8f83SChunfeng Yun } 391c1eb8f83SChunfeng Yun 392c1eb8f83SChunfeng Yun static struct phy *mtk_phy_xlate(struct device *dev, 393c1eb8f83SChunfeng Yun struct of_phandle_args *args) 394c1eb8f83SChunfeng Yun { 395c1eb8f83SChunfeng Yun struct mtk_xsphy *xsphy = dev_get_drvdata(dev); 396c1eb8f83SChunfeng Yun struct xsphy_instance *inst = NULL; 397c1eb8f83SChunfeng Yun struct device_node *phy_np = args->np; 398c1eb8f83SChunfeng Yun int index; 399c1eb8f83SChunfeng Yun 400c1eb8f83SChunfeng Yun if (args->args_count != 1) { 401c1eb8f83SChunfeng Yun dev_err(dev, "invalid number of cells in 'phy' property\n"); 402c1eb8f83SChunfeng Yun return ERR_PTR(-EINVAL); 403c1eb8f83SChunfeng Yun } 404c1eb8f83SChunfeng Yun 405c1eb8f83SChunfeng Yun for (index = 0; index < xsphy->nphys; index++) 406c1eb8f83SChunfeng Yun if (phy_np == xsphy->phys[index]->phy->dev.of_node) { 407c1eb8f83SChunfeng Yun inst = xsphy->phys[index]; 408c1eb8f83SChunfeng Yun break; 409c1eb8f83SChunfeng Yun } 410c1eb8f83SChunfeng Yun 411c1eb8f83SChunfeng Yun if (!inst) { 412c1eb8f83SChunfeng Yun dev_err(dev, "failed to find appropriate phy\n"); 413c1eb8f83SChunfeng Yun return ERR_PTR(-EINVAL); 414c1eb8f83SChunfeng Yun } 415c1eb8f83SChunfeng Yun 416c1eb8f83SChunfeng Yun inst->type = args->args[0]; 417c1eb8f83SChunfeng Yun if (!(inst->type == PHY_TYPE_USB2 || 418c1eb8f83SChunfeng Yun inst->type == PHY_TYPE_USB3)) { 419c1eb8f83SChunfeng Yun dev_err(dev, "unsupported phy type: %d\n", inst->type); 420c1eb8f83SChunfeng Yun return ERR_PTR(-EINVAL); 421c1eb8f83SChunfeng Yun } 422c1eb8f83SChunfeng Yun 423c1eb8f83SChunfeng Yun phy_parse_property(xsphy, inst); 424c1eb8f83SChunfeng Yun 425c1eb8f83SChunfeng Yun return inst->phy; 426c1eb8f83SChunfeng Yun } 427c1eb8f83SChunfeng Yun 428c1eb8f83SChunfeng Yun static const struct phy_ops mtk_xsphy_ops = { 429c1eb8f83SChunfeng Yun .init = mtk_phy_init, 430c1eb8f83SChunfeng Yun .exit = mtk_phy_exit, 431c1eb8f83SChunfeng Yun .power_on = mtk_phy_power_on, 432c1eb8f83SChunfeng Yun .power_off = mtk_phy_power_off, 433c1eb8f83SChunfeng Yun .set_mode = mtk_phy_set_mode, 434c1eb8f83SChunfeng Yun .owner = THIS_MODULE, 435c1eb8f83SChunfeng Yun }; 436c1eb8f83SChunfeng Yun 437c1eb8f83SChunfeng Yun static const struct of_device_id mtk_xsphy_id_table[] = { 438c1eb8f83SChunfeng Yun { .compatible = "mediatek,xsphy", }, 439c1eb8f83SChunfeng Yun { }, 440c1eb8f83SChunfeng Yun }; 441c1eb8f83SChunfeng Yun MODULE_DEVICE_TABLE(of, mtk_xsphy_id_table); 442c1eb8f83SChunfeng Yun 443c1eb8f83SChunfeng Yun static int mtk_xsphy_probe(struct platform_device *pdev) 444c1eb8f83SChunfeng Yun { 445c1eb8f83SChunfeng Yun struct device *dev = &pdev->dev; 446c1eb8f83SChunfeng Yun struct device_node *np = dev->of_node; 447c1eb8f83SChunfeng Yun struct device_node *child_np; 448c1eb8f83SChunfeng Yun struct phy_provider *provider; 449c1eb8f83SChunfeng Yun struct resource *glb_res; 450c1eb8f83SChunfeng Yun struct mtk_xsphy *xsphy; 451c1eb8f83SChunfeng Yun struct resource res; 452c1eb8f83SChunfeng Yun int port, retval; 453c1eb8f83SChunfeng Yun 454c1eb8f83SChunfeng Yun xsphy = devm_kzalloc(dev, sizeof(*xsphy), GFP_KERNEL); 455c1eb8f83SChunfeng Yun if (!xsphy) 456c1eb8f83SChunfeng Yun return -ENOMEM; 457c1eb8f83SChunfeng Yun 458c1eb8f83SChunfeng Yun xsphy->nphys = of_get_child_count(np); 459c1eb8f83SChunfeng Yun xsphy->phys = devm_kcalloc(dev, xsphy->nphys, 460c1eb8f83SChunfeng Yun sizeof(*xsphy->phys), GFP_KERNEL); 461c1eb8f83SChunfeng Yun if (!xsphy->phys) 462c1eb8f83SChunfeng Yun return -ENOMEM; 463c1eb8f83SChunfeng Yun 464c1eb8f83SChunfeng Yun xsphy->dev = dev; 465c1eb8f83SChunfeng Yun platform_set_drvdata(pdev, xsphy); 466c1eb8f83SChunfeng Yun 467c1eb8f83SChunfeng Yun glb_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 468c1eb8f83SChunfeng Yun /* optional, may not exist if no u3 phys */ 469c1eb8f83SChunfeng Yun if (glb_res) { 470c1eb8f83SChunfeng Yun /* get banks shared by multiple u3 phys */ 471c1eb8f83SChunfeng Yun xsphy->glb_base = devm_ioremap_resource(dev, glb_res); 472c1eb8f83SChunfeng Yun if (IS_ERR(xsphy->glb_base)) { 473c1eb8f83SChunfeng Yun dev_err(dev, "failed to remap glb regs\n"); 474c1eb8f83SChunfeng Yun return PTR_ERR(xsphy->glb_base); 475c1eb8f83SChunfeng Yun } 476c1eb8f83SChunfeng Yun } 477c1eb8f83SChunfeng Yun 478c1eb8f83SChunfeng Yun xsphy->src_ref_clk = XSP_REF_CLK; 479c1eb8f83SChunfeng Yun xsphy->src_coef = XSP_SLEW_RATE_COEF; 480c1eb8f83SChunfeng Yun /* update parameters of slew rate calibrate if exist */ 481c1eb8f83SChunfeng Yun device_property_read_u32(dev, "mediatek,src-ref-clk-mhz", 482c1eb8f83SChunfeng Yun &xsphy->src_ref_clk); 483c1eb8f83SChunfeng Yun device_property_read_u32(dev, "mediatek,src-coef", &xsphy->src_coef); 484c1eb8f83SChunfeng Yun 485c1eb8f83SChunfeng Yun port = 0; 486c1eb8f83SChunfeng Yun for_each_child_of_node(np, child_np) { 487c1eb8f83SChunfeng Yun struct xsphy_instance *inst; 488c1eb8f83SChunfeng Yun struct phy *phy; 489c1eb8f83SChunfeng Yun 490c1eb8f83SChunfeng Yun inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL); 491c1eb8f83SChunfeng Yun if (!inst) { 492c1eb8f83SChunfeng Yun retval = -ENOMEM; 493c1eb8f83SChunfeng Yun goto put_child; 494c1eb8f83SChunfeng Yun } 495c1eb8f83SChunfeng Yun 496c1eb8f83SChunfeng Yun xsphy->phys[port] = inst; 497c1eb8f83SChunfeng Yun 498c1eb8f83SChunfeng Yun phy = devm_phy_create(dev, child_np, &mtk_xsphy_ops); 499c1eb8f83SChunfeng Yun if (IS_ERR(phy)) { 500c1eb8f83SChunfeng Yun dev_err(dev, "failed to create phy\n"); 501c1eb8f83SChunfeng Yun retval = PTR_ERR(phy); 502c1eb8f83SChunfeng Yun goto put_child; 503c1eb8f83SChunfeng Yun } 504c1eb8f83SChunfeng Yun 505c1eb8f83SChunfeng Yun retval = of_address_to_resource(child_np, 0, &res); 506c1eb8f83SChunfeng Yun if (retval) { 507c1eb8f83SChunfeng Yun dev_err(dev, "failed to get address resource(id-%d)\n", 508c1eb8f83SChunfeng Yun port); 509c1eb8f83SChunfeng Yun goto put_child; 510c1eb8f83SChunfeng Yun } 511c1eb8f83SChunfeng Yun 512c1eb8f83SChunfeng Yun inst->port_base = devm_ioremap_resource(&phy->dev, &res); 513c1eb8f83SChunfeng Yun if (IS_ERR(inst->port_base)) { 514c1eb8f83SChunfeng Yun dev_err(dev, "failed to remap phy regs\n"); 515c1eb8f83SChunfeng Yun retval = PTR_ERR(inst->port_base); 516c1eb8f83SChunfeng Yun goto put_child; 517c1eb8f83SChunfeng Yun } 518c1eb8f83SChunfeng Yun 519c1eb8f83SChunfeng Yun inst->phy = phy; 520c1eb8f83SChunfeng Yun inst->index = port; 521c1eb8f83SChunfeng Yun phy_set_drvdata(phy, inst); 522c1eb8f83SChunfeng Yun port++; 523c1eb8f83SChunfeng Yun 524c1eb8f83SChunfeng Yun inst->ref_clk = devm_clk_get(&phy->dev, "ref"); 525c1eb8f83SChunfeng Yun if (IS_ERR(inst->ref_clk)) { 526c1eb8f83SChunfeng Yun dev_err(dev, "failed to get ref_clk(id-%d)\n", port); 527c1eb8f83SChunfeng Yun retval = PTR_ERR(inst->ref_clk); 528c1eb8f83SChunfeng Yun goto put_child; 529c1eb8f83SChunfeng Yun } 530c1eb8f83SChunfeng Yun } 531c1eb8f83SChunfeng Yun 532c1eb8f83SChunfeng Yun provider = devm_of_phy_provider_register(dev, mtk_phy_xlate); 533c1eb8f83SChunfeng Yun return PTR_ERR_OR_ZERO(provider); 534c1eb8f83SChunfeng Yun 535c1eb8f83SChunfeng Yun put_child: 536c1eb8f83SChunfeng Yun of_node_put(child_np); 537c1eb8f83SChunfeng Yun return retval; 538c1eb8f83SChunfeng Yun } 539c1eb8f83SChunfeng Yun 540c1eb8f83SChunfeng Yun static struct platform_driver mtk_xsphy_driver = { 541c1eb8f83SChunfeng Yun .probe = mtk_xsphy_probe, 542c1eb8f83SChunfeng Yun .driver = { 543c1eb8f83SChunfeng Yun .name = "mtk-xsphy", 544c1eb8f83SChunfeng Yun .of_match_table = mtk_xsphy_id_table, 545c1eb8f83SChunfeng Yun }, 546c1eb8f83SChunfeng Yun }; 547c1eb8f83SChunfeng Yun 548c1eb8f83SChunfeng Yun module_platform_driver(mtk_xsphy_driver); 549c1eb8f83SChunfeng Yun 550c1eb8f83SChunfeng Yun MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>"); 551c1eb8f83SChunfeng Yun MODULE_DESCRIPTION("MediaTek USB XS-PHY driver"); 552c1eb8f83SChunfeng Yun MODULE_LICENSE("GPL v2"); 553