/* * Copyright (c) 2015 Samsung Electronics Co., Ltd. * http://www.samsung.com * * Author: Sung-Hyun Na * Author: Minho Lee * * Chip Abstraction Layer for USB PHY * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifdef __KERNEL__ #ifndef __EXCITE__ #include #include #endif #include #else #include "types.h" #include "customfunctions.h" #include "mct.h" #endif #include "phy-samsung-usb-cal.h" #include "phy-samsung-usb3-cal.h" #define USB_SS_TX_TUNE_PCS //#define USB_MUX_UTMI_ENABLE enum exynos_usbcon_cr { USBCON_CR_ADDR = 0, USBCON_CR_DATA = 1, USBCON_CR_READ = 18, USBCON_CR_WRITE = 19, }; static u16 samsung_exynos_cal_cr_access(struct exynos_usbphy_info *usbphy_info, enum exynos_usbcon_cr cr_bit, u16 data) { void __iomem *base; u32 phyreg0; u32 phyreg1; u32 loop; u32 loop_cnt; if (usbphy_info->used_phy_port != -1) { if (usbphy_info->used_phy_port == 0) base = usbphy_info->regs_base; else base = usbphy_info->regs_base_2nd; } else base = usbphy_info->regs_base; /* Clear CR port register */ phyreg0 = readl(base + EXYNOS_USBCON_PHYREG0); phyreg0 &= ~(0xfffff); writel(phyreg0, base + EXYNOS_USBCON_PHYREG0); /* Set Data for cr port */ phyreg0 &= ~PHYREG0_CR_DATA_MASK; phyreg0 |= PHYREG0_CR_DATA_IN(data); writel(phyreg0, base + EXYNOS_USBCON_PHYREG0); if (cr_bit == USBCON_CR_ADDR) loop = 1; else loop = 2; for (loop_cnt = 0; loop_cnt < loop; loop_cnt++) { u32 trigger_bit = 0; u32 handshake_cnt = 2; /* Trigger cr port */ if (cr_bit == USBCON_CR_ADDR) trigger_bit = PHYREG0_CR_CR_CAP_ADDR; else { if (loop_cnt == 0) trigger_bit = PHYREG0_CR_CR_CAP_DATA; else { if (cr_bit == USBCON_CR_READ) trigger_bit = PHYREG0_CR_READ; else trigger_bit = PHYREG0_CR_WRITE; } } /* Handshake Procedure */ do { u32 usec = 100; if (handshake_cnt == 2) phyreg0 |= trigger_bit; else phyreg0 &= ~trigger_bit; writel(phyreg0, base + EXYNOS_USBCON_PHYREG0); /* Handshake */ do { phyreg1 = readl(base + EXYNOS_USBCON_PHYREG1); if ((handshake_cnt == 2) && (phyreg1 & PHYREG1_CR_ACK)) break; else if ((handshake_cnt == 1) && !(phyreg1 & PHYREG1_CR_ACK)) break; udelay(1); } while (usec-- > 0); if (!usec) pr_err("CRPORT handshake timeout1 (0x%08x)\n", phyreg0); udelay(5); handshake_cnt--; } while (handshake_cnt != 0); udelay(50); } return (u16) ((phyreg1 & PHYREG1_CR_DATA_OUT_MASK) >> 1); } void samsung_exynos_cal_cr_write(struct exynos_usbphy_info *usbphy_info, u16 addr, u16 data) { samsung_exynos_cal_cr_access(usbphy_info, USBCON_CR_ADDR, addr); samsung_exynos_cal_cr_access(usbphy_info, USBCON_CR_WRITE, data); } u16 samsung_exynos_cal_cr_read(struct exynos_usbphy_info *usbphy_info, u16 addr) { samsung_exynos_cal_cr_access(usbphy_info, USBCON_CR_ADDR, addr); return samsung_exynos_cal_cr_access(usbphy_info, USBCON_CR_READ, 0); } void samsung_exynos_cal_usb3phy_tune_fix_rxeq( struct exynos_usbphy_info *usbphy_info) { u16 reg; struct exynos_usbphy_ss_tune *tune = usbphy_info->ss_tune; if (!tune) return; reg = samsung_exynos_cal_cr_read(usbphy_info, 0x1006); reg &= ~(1 << 6); samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg); udelay(10); reg |= (1 << 7); samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg); udelay(10); reg &= ~(0x7 << 0x8); reg |= (tune->fix_rxeq_value << 8); samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg); udelay(10); reg |= (1 << 11); samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg); printk("Reg RX_OVRD_IN_HI : 0x%x\n", samsung_exynos_cal_cr_read(usbphy_info, 0x1006)); printk("Reg RX_CDR_CDR_FSM_DEBUG : 0x%x\n", samsung_exynos_cal_cr_read(usbphy_info, 0x101c)); } static void set_ss_tx_impedance(struct exynos_usbphy_info *usbphy_info) { u16 rtune_debug, tx_ovrd_in_hi; u8 tx_imp; /* obtain calibration code for 45Ohm impedance */ rtune_debug = samsung_exynos_cal_cr_read(usbphy_info, 0x3); /* set SUP.DIG.RTUNE_DEBUG.TYPE = 2 */ rtune_debug &= ~(0x3 << 3); rtune_debug |= (0x2 << 3); samsung_exynos_cal_cr_write(usbphy_info, 0x3, rtune_debug); /* read SUP.DIG.RTUNE_STAT (0x0004[9:0]) */ tx_imp = samsung_exynos_cal_cr_read(usbphy_info, 0x4); /* current_tx_cal_code[9:0] = SUP.DIG.RTUNE_STAT (0x0004[9:0]) */ tx_imp += 8; /* tx_cal_code[9:0] = current_tx_cal_code[9:0] + 8(decimal) * NOTE, max value is 63; * i.e. if tx_cal_code[9:0] > 63, tx_cal_code[9:0]==63; */ if (tx_imp > 63) tx_imp = 63; /* set LANEX_DIG_TX_OVRD_IN_HI.TX_RESET_OVRD = 1 */ tx_ovrd_in_hi = samsung_exynos_cal_cr_read(usbphy_info, 0x1001); tx_ovrd_in_hi |= (1 << 7); samsung_exynos_cal_cr_write(usbphy_info, 0x1001, tx_ovrd_in_hi); /* SUP.DIG.RTUNE_DEBUG.MAN_TUNE = 0 */ rtune_debug &= ~(1 << 1); samsung_exynos_cal_cr_write(usbphy_info, 0x3, rtune_debug); /* set SUP.DIG.RTUNE_DEBUG.VALUE = tx_cal_code[9:0] */ rtune_debug &= ~(0x1ff << 5); rtune_debug |= (tx_imp << 5); samsung_exynos_cal_cr_write(usbphy_info, 0x3, rtune_debug); /* set SUP.DIG.RTUNE_DEBUG.SET_VAL = 1 */ rtune_debug |= (1 << 2); samsung_exynos_cal_cr_write(usbphy_info, 0x3, rtune_debug); /* set SUP.DIG.RTUNE_DEBUG.SET_VAL = 0 */ rtune_debug &= ~(1 << 2); samsung_exynos_cal_cr_write(usbphy_info, 0x3, rtune_debug); /* set LANEX_DIG_TX_OVRD_IN_HI.TX_RESET = 1 */ tx_ovrd_in_hi |= (1 << 6); samsung_exynos_cal_cr_write(usbphy_info, 0x1001, tx_ovrd_in_hi); /* set LANEX_DIG_TX_OVRD_IN_HI.TX_RESET = 0 */ tx_ovrd_in_hi &= ~(1 << 6); samsung_exynos_cal_cr_write(usbphy_info, 0x1001, tx_ovrd_in_hi); } void samsung_exynos_cal_usb3phy_tune_adaptive_eq( struct exynos_usbphy_info *usbphy_info, u8 eq_fix) { u16 reg; reg = samsung_exynos_cal_cr_read(usbphy_info, 0x1006); if (eq_fix) { reg |= (1 << 6); reg &= ~(1 << 7); } else { reg &= ~(1 << 6); reg |= (1 << 7); } samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg); } void samsung_exynos_cal_usb3phy_tune_chg_rxeq( struct exynos_usbphy_info *usbphy_info, u8 eq_val) { u16 reg; reg = samsung_exynos_cal_cr_read(usbphy_info, 0x1006); reg &= ~(0x7 << 0x8); reg |= ((eq_val & 0x7) << 8); reg |= (1 << 11); samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg); } static void exynos_cal_ss_enable(struct exynos_usbphy_info *info, u32 *arg_phyclkrst, u8 port_num) { u32 phyclkrst = *arg_phyclkrst; u32 phypipe; u32 phyparam0; u32 phyreg0; void *reg_base; if (port_num == 0) reg_base = info->regs_base; else reg_base = info->regs_base_2nd; if (info->version < EXYNOS_USBCON_VER_01_0_1) phyclkrst |= PHYCLKRST_COMMONONN; /* Disable Common block control by link */ phyclkrst &= ~PHYCLKRST_EN_UTMISUSPEND; /* Digital Supply Mode : normal operating mode */ phyclkrst |= PHYCLKRST_RETENABLEN; /* ref. clock enable for ss function */ phyclkrst |= PHYCLKRST_REF_SSP_EN; phyparam0 = readl(info->regs_base + EXYNOS_USBCON_PHYPARAM0); if (info->refsel == USBPHY_REFSEL_DIFF_PAD) phyparam0 |= PHYPARAM0_REF_USE_PAD; else phyparam0 &= ~PHYPARAM0_REF_USE_PAD; writel(phyparam0, reg_base + EXYNOS_USBCON_PHYPARAM0); if (info->version >= EXYNOS_USBCON_VER_01_0_1) phyreg0 = readl(reg_base + EXYNOS_USBCON_PHYREG0); switch (info->refclk) { case USBPHY_REFCLK_DIFF_100MHZ: phyclkrst &= ~PHYCLKRST_MPLL_MULTIPLIER_MASK; phyclkrst |= PHYCLKRST_MPLL_MULTIPLIER(0x00); phyclkrst &= ~PHYCLKRST_REF_CLKDIV2; if (info->version == EXYNOS_USBCON_VER_01_0_1) { phyreg0 &= ~PHYREG0_SSC_REFCLKSEL_MASK; phyreg0 |= PHYREG0_SSC_REFCLKSEL(0x00); } else { phyclkrst &= ~PHYCLKRST_SSC_REFCLKSEL_MASK; phyclkrst |= PHYCLKRST_SSC_REFCLKSEL(0x00); } break; case USBPHY_REFCLK_DIFF_26MHZ: case USBPHY_REFCLK_DIFF_52MHZ: phyclkrst &= ~PHYCLKRST_MPLL_MULTIPLIER_MASK; phyclkrst |= PHYCLKRST_MPLL_MULTIPLIER(0x60); if (info->refclk & 0x40) phyclkrst |= PHYCLKRST_REF_CLKDIV2; else phyclkrst &= ~PHYCLKRST_REF_CLKDIV2; if (info->version == EXYNOS_USBCON_VER_01_0_1) { phyreg0 &= ~PHYREG0_SSC_REFCLKSEL_MASK; phyreg0 |= PHYREG0_SSC_REFCLKSEL(0x108); } else { phyclkrst &= ~PHYCLKRST_SSC_REFCLKSEL_MASK; phyclkrst |= PHYCLKRST_SSC_REFCLKSEL(0x108); } break; case USBPHY_REFCLK_DIFF_24MHZ: case USBPHY_REFCLK_EXT_24MHZ: phyclkrst &= ~PHYCLKRST_MPLL_MULTIPLIER_MASK; phyclkrst |= PHYCLKRST_MPLL_MULTIPLIER(0x00); phyclkrst &= ~PHYCLKRST_REF_CLKDIV2; if (info->version != EXYNOS_USBCON_VER_01_0_1) { phyclkrst &= ~PHYCLKRST_SSC_REFCLKSEL_MASK; phyclkrst |= PHYCLKRST_SSC_REFCLKSEL(0x88); } else { phyreg0 &= ~PHYREG0_SSC_REFCLKSEL_MASK; phyreg0 |= PHYREG0_SSC_REFCLKSEL(0x88); } break; case USBPHY_REFCLK_DIFF_20MHZ: case USBPHY_REFCLK_DIFF_19_2MHZ: phyclkrst &= ~PHYCLKRST_MPLL_MULTIPLIER_MASK; phyclkrst &= ~PHYCLKRST_REF_CLKDIV2; if (info->version == EXYNOS_USBCON_VER_01_0_1) phyreg0 &= ~PHYREG0_SSC_REFCLKSEL_MASK; else phyclkrst &= ~PHYCLKRST_SSC_REFCLKSEL_MASK; break; default: break; } /* SSC Enable */ if (info->ss_tune) { u32 range = info->ss_tune->ssc_range; if (info->ss_tune->enable_ssc) phyclkrst |= PHYCLKRST_SSC_EN; else phyclkrst &= ~PHYCLKRST_SSC_EN; if (info->version != EXYNOS_USBCON_VER_01_0_1) { phyclkrst &= ~PHYCLKRST_SSC_RANGE_MASK; phyclkrst |= PHYCLKRST_SSC_RANGE(range); } else { phyreg0 &= ~PHYREG0_SSC_RANGE_MASK; phyreg0 |= PHYREG0_SSC_RAMGE(range); } } else { /* Default Value : SSC Enable */ phyclkrst |= PHYCLKRST_SSC_EN; if (info->version != EXYNOS_USBCON_VER_01_0_1) { phyclkrst &= ~PHYCLKRST_SSC_RANGE_MASK; phyclkrst |= PHYCLKRST_SSC_RANGE(0x0); } else { phyreg0 &= ~PHYREG0_SSC_RANGE_MASK; phyreg0 |= PHYREG0_SSC_RAMGE(0x0); } } /* Select UTMI CLOCK 0 : PHY CLOCK, 1 : FREE CLOCK */ phypipe = readl(reg_base + EXYNOS_USBCON_PHYPIPE); phypipe |= PHY_CLOCK_SEL; writel(phypipe, reg_base + EXYNOS_USBCON_PHYPIPE); if (info->version >= EXYNOS_USBCON_VER_01_0_1) writel(phyreg0, reg_base + EXYNOS_USBCON_PHYREG0); *arg_phyclkrst = phyclkrst; } static void exynos_cal_ss_power_down(struct exynos_usbphy_info *info, bool en) { u32 phytest; phytest = readl(info->regs_base + EXYNOS_USBCON_PHYTEST); if (en == 1) { phytest &= ~PHYTEST_POWERDOWN_HSP; phytest &= ~PHYTEST_POWERDOWN_SSP; writel(phytest, info->regs_base + EXYNOS_USBCON_PHYTEST); if (info->used_phy_port == 1) { void *reg_base = info->regs_base_2nd; phytest |= PHYTEST_POWERDOWN_SSP; writel(phytest, info->regs_base + EXYNOS_USBCON_PHYTEST); phytest = readl(reg_base + EXYNOS_USBCON_PHYTEST); phytest &= ~PHYTEST_POWERDOWN_HSP; phytest &= ~PHYTEST_POWERDOWN_SSP; writel(phytest, reg_base + EXYNOS_USBCON_PHYTEST); } } else { phytest |= PHYTEST_POWERDOWN_HSP; phytest |= PHYTEST_POWERDOWN_SSP; writel(phytest, info->regs_base + EXYNOS_USBCON_PHYTEST); if (info->used_phy_port == 1) { void *reg_base = info->regs_base_2nd; phytest = readl(reg_base + EXYNOS_USBCON_PHYTEST); phytest |= PHYTEST_POWERDOWN_HSP; phytest |= PHYTEST_POWERDOWN_SSP; writel(phytest, reg_base + EXYNOS_USBCON_PHYTEST); } } } static void exynos_cal_hs_enable(struct exynos_usbphy_info *info, u32 *arg_phyclkrst) { u32 phyclkrst = *arg_phyclkrst; u32 hsphyplltune = readl(info->regs_base + EXYNOS_USBCON_HSPHYPLLTUNE); if ((info->version & 0xf0) >= 0x10) { /* Disable Common block control by link */ phyclkrst |= PHYCLKRST_EN_UTMISUSPEND; phyclkrst |= PHYCLKRST_COMMONONN; } else { phyclkrst |= PHYCLKRST_EN_UTMISUSPEND; phyclkrst |= PHYCLKRST_COMMONONN; } /* Change PHY PLL Tune value */ if (info->refclk == USBPHY_REFCLK_EXT_24MHZ) hsphyplltune |= HSPHYPLLTUNE_PLL_B_TUNE; else hsphyplltune &= ~HSPHYPLLTUNE_PLL_B_TUNE; hsphyplltune |= HSPHYPLLTUNE_PLL_P_TUNE(0xe); writel(hsphyplltune, info->regs_base + EXYNOS_USBCON_HSPHYPLLTUNE); *arg_phyclkrst = phyclkrst; } static void exynos_cal_hs_power_down(struct exynos_usbphy_info *info, bool en) { u32 hsphyctrl; hsphyctrl = readl(info->regs_base + EXYNOS_USBCON_HSPHYCTRL); if (en) { hsphyctrl &= ~HSPHYCTRL_SIDDQ; hsphyctrl &= ~HSPHYCTRL_PHYSWRST; hsphyctrl &= ~HSPHYCTRL_PHYSWRSTALL; } else { hsphyctrl |= HSPHYCTRL_SIDDQ; } writel(hsphyctrl, info->regs_base + EXYNOS_USBCON_HSPHYCTRL); } static void exynos_cal_usbphy_q_ch(void *regs_base, u8 enable) { u32 phy_resume; if (enable) { /* WA for Q-channel: disable all q-act from usb */ phy_resume = readl(regs_base + EXYNOS_USBCON_PHYRESUME); phy_resume |= PHYRESUME_DIS_ID0_QACT; phy_resume |= PHYRESUME_DIS_VBUSVALID_QACT; phy_resume |= PHYRESUME_DIS_BVALID_QACT; phy_resume |= PHYRESUME_DIS_LINKGATE_QACT; //phy_resume |= PHYRESUME_DIS_BUSPEND_QACT; phy_resume &= ~PHYRESUME_FORCE_QACT; udelay(500); writel(phy_resume, regs_base + EXYNOS_USBCON_PHYRESUME); udelay(500); phy_resume = readl(regs_base + EXYNOS_USBCON_PHYRESUME); phy_resume |= PHYRESUME_FORCE_QACT; udelay(500); writel(phy_resume, regs_base + EXYNOS_USBCON_PHYRESUME); } else { phy_resume = readl(regs_base + EXYNOS_USBCON_PHYRESUME); phy_resume &= ~PHYRESUME_FORCE_QACT; phy_resume |= PHYRESUME_DIS_ID0_QACT; phy_resume |= PHYRESUME_DIS_VBUSVALID_QACT; phy_resume |= PHYRESUME_DIS_BVALID_QACT; phy_resume |= PHYRESUME_DIS_LINKGATE_QACT; //phy_resume |= PHYRESUME_DIS_BUSPEND_QACT; writel(phy_resume, regs_base + EXYNOS_USBCON_PHYRESUME); } } void samsung_exynos_cal_usb3phy_enable(struct exynos_usbphy_info *usbphy_info) { void __iomem *regs_base = usbphy_info->regs_base; u32 version = usbphy_info->version; enum exynos_usbphy_refclk refclkfreq = usbphy_info->refclk; u32 phyutmi; u32 phyclkrst; u32 linkport; /* check phycon version */ if (!usbphy_info->hw_version) { u32 phyversion = readl(regs_base); if (!phyversion) { usbphy_info->hw_version = -1; usbphy_info->used_phy_port = -1; } else { usbphy_info->hw_version = phyversion; usbphy_info->regs_base += 4; regs_base = usbphy_info->regs_base; if (usbphy_info->regs_base_2nd) usbphy_info->regs_base_2nd += 4; } } /* Set force q-channel */ if ((version & 0xf) >= 0x01) exynos_cal_usbphy_q_ch(regs_base, 1); /* Select PHY MUX */ if (usbphy_info->used_phy_port != -1) { u32 physel; physel = readl(regs_base + EXYNOS_USBCON_PHYSELECTION); if (usbphy_info->used_phy_port == 0) { physel &= ~PHYSEL_PIPE; physel &= ~PHYSEL_PIPE_CLK; #if defined(USB_MUX_UTMI_ENABLE) /* UE_TASK: for utmi 2nd port test : will be removed */ physel &= ~PHYSEL_UTMI_CLK; physel &= ~PHYSEL_UTMI; physel &= ~PHYSEL_SIDEBAND; #endif } else { physel |= PHYSEL_PIPE; physel |= PHYSEL_PIPE_CLK; #if defined(USB_MUX_UTMI_ENABLE) /* UE_TASK: for utmi 2nd port test : will be removed */ physel |= PHYSEL_UTMI_CLK; physel |= PHYSEL_UTMI; physel |= PHYSEL_SIDEBAND; #endif } writel(physel, regs_base + EXYNOS_USBCON_PHYSELECTION); } /* set phy clock & control HS phy */ phyclkrst = readl(regs_base + EXYNOS_USBCON_PHYCLKRST); /* assert port_reset */ phyclkrst |= PHYCLKRST_PORTRESET; /* Select Reference clock source path */ phyclkrst &= ~PHYCLKRST_REFCLKSEL_MASK; phyclkrst |= PHYCLKRST_REFCLKSEL(usbphy_info->refsel); /* Select ref clk */ phyclkrst &= ~PHYCLKRST_FSEL_MASK; phyclkrst |= PHYCLKRST_FSEL(refclkfreq & 0x3f); /* Enable Common Block in suspend/sleep mode */ phyclkrst &= ~PHYCLKRST_COMMONONN; /* Additional control for 3.0 PHY */ if ((EXYNOS_USBCON_VER_01_0_0 <= version) && (version <= EXYNOS_USBCON_VER_01_MAX)) { exynos_cal_ss_enable(usbphy_info, &phyclkrst, 0); /* select used phy port */ if (usbphy_info->used_phy_port == 1) { void *reg_2nd = usbphy_info->regs_base_2nd; exynos_cal_ss_enable(usbphy_info, &phyclkrst, 1); writel(phyclkrst, reg_2nd + EXYNOS_USBCON_PHYCLKRST); udelay(10); phyclkrst &= ~PHYCLKRST_PORTRESET; writel(phyclkrst, reg_2nd + EXYNOS_USBCON_PHYCLKRST); phyclkrst |= PHYCLKRST_PORTRESET; } } else if ((EXYNOS_USBCON_VER_02_0_0 <= version) && (version <= EXYNOS_USBCON_VER_02_MAX)) exynos_cal_hs_enable(usbphy_info, &phyclkrst); writel(phyclkrst, regs_base + EXYNOS_USBCON_PHYCLKRST); udelay(10); phyclkrst &= ~PHYCLKRST_PORTRESET; writel(phyclkrst, regs_base + EXYNOS_USBCON_PHYCLKRST); if ((EXYNOS_USBCON_VER_01_0_0 <= version) && (version <= EXYNOS_USBCON_VER_01_MAX)) { exynos_cal_ss_power_down(usbphy_info, 1); } else if (version >= EXYNOS_USBCON_VER_02_0_0 && version <= EXYNOS_USBCON_VER_02_MAX) { exynos_cal_hs_power_down(usbphy_info, 1); } udelay(500); /* release force_sleep & force_suspend */ phyutmi = readl(regs_base + EXYNOS_USBCON_PHYUTMI); phyutmi &= ~PHYUTMI_FORCESLEEP; phyutmi &= ~PHYUTMI_FORCESUSPEND; /* DP/DM Pull Down Control */ phyutmi &= ~PHYUTMI_DMPULLDOWN; phyutmi &= ~PHYUTMI_DPPULLDOWN; /* Set VBUSVALID signal if VBUS pad is not used */ if (usbphy_info->not_used_vbus_pad) { u32 linksystem; linksystem = readl(regs_base + EXYNOS_USBCON_LINKSYSTEM); linksystem |= LINKSYSTEM_FORCE_BVALID; linksystem |= LINKSYSTEM_FORCE_VBUSVALID; writel(linksystem, regs_base + EXYNOS_USBCON_LINKSYSTEM); #if defined(USB_MUX_UTMI_ENABLE) /* UE_TASK: for utmi 2nd port test : will be removed */ if (usbphy_info->regs_base_2nd && usbphy_info->used_phy_port == 1) { linksystem = readl(usbphy_info->regs_base_2nd + EXYNOS_USBCON_LINKSYSTEM); linksystem |= LINKSYSTEM_FORCE_BVALID; linksystem |= LINKSYSTEM_FORCE_VBUSVALID; writel(linksystem, usbphy_info->regs_base_2nd + EXYNOS_USBCON_LINKSYSTEM); } #endif phyutmi |= PHYUTMI_VBUSVLDEXTSEL; phyutmi |= PHYUTMI_VBUSVLDEXT; } /* disable OTG block and VBUS valid comparator */ phyutmi &= ~PHYUTMI_DRVVBUS; phyutmi |= PHYUTMI_OTGDISABLE; writel(phyutmi, regs_base + EXYNOS_USBCON_PHYUTMI); #if defined(USB_MUX_UTMI_ENABLE) /* UE_TASK: for utmi 2nd port test : will be removed */ if (usbphy_info->regs_base_2nd && usbphy_info->used_phy_port == 1) writel(phyutmi, usbphy_info->regs_base_2nd + EXYNOS_USBCON_PHYUTMI); #endif /* OVC io usage */ linkport = readl(regs_base + EXYNOS_USBCON_LINKPORT); if (usbphy_info->use_io_for_ovc) { linkport &= ~LINKPORT_HOST_PORT_OVCR_U3_SEL; linkport &= ~LINKPORT_HOST_PORT_OVCR_U2_SEL; } else { linkport |= LINKPORT_HOST_PORT_OVCR_U3_SEL; linkport |= LINKPORT_HOST_PORT_OVCR_U2_SEL; } writel(linkport, regs_base + EXYNOS_USBCON_LINKPORT); if ((EXYNOS_USBCON_VER_02_0_0 <= version) && (version <= EXYNOS_USBCON_VER_02_MAX)) { u32 hsphyctrl; hsphyctrl = readl(regs_base + EXYNOS_USBCON_HSPHYCTRL); hsphyctrl |= HSPHYCTRL_PHYSWRST; writel(hsphyctrl, regs_base + EXYNOS_USBCON_HSPHYCTRL); udelay(20); hsphyctrl = readl(regs_base + EXYNOS_USBCON_HSPHYCTRL); hsphyctrl &= ~HSPHYCTRL_PHYSWRST; writel(hsphyctrl, regs_base + EXYNOS_USBCON_HSPHYCTRL); } } void samsung_exynos_cal_usb3phy_late_enable( struct exynos_usbphy_info *usbphy_info) { u32 version = usbphy_info->version; struct exynos_usbphy_ss_tune *tune = usbphy_info->ss_tune; if (EXYNOS_USBCON_VER_01_0_0 <= version && version <= EXYNOS_USBCON_VER_01_MAX) { /* Set RXDET_MEAS_TIME[11:4] each reference clock */ samsung_exynos_cal_cr_write(usbphy_info, 0x1010, 0x80); printk("Check CR Port write 0x1010: 0x%x\n", samsung_exynos_cal_cr_read(usbphy_info, 0x1010)); if (tune) { #if defined(USB_SS_TX_TUNE_PCS) samsung_exynos_cal_cr_write(usbphy_info, 0x1002, 0x4000 | (tune->tx_deemphasis_3p5db << 7) | tune->tx_swing_full); #else samsung_exynos_cal_cr_write(usbphy_info, 0x1002, 0x0); #endif /* Set RX_SCOPE_LFPS_EN */ if (tune->rx_decode_mode) { samsung_exynos_cal_cr_write(usbphy_info, 0x1026, 0x1); } if (tune->set_crport_level_en) { /* Enable override los_bias, los_level and * tx_vboost_lvl, Set los_bias to 0x5 and * los_level to 0x9 */ samsung_exynos_cal_cr_write(usbphy_info, 0x15, 0xA409); /* Set TX_VBOOST_LEVLE to default Value (0x4) */ samsung_exynos_cal_cr_write(usbphy_info, 0x12, 0x8000); } /* to set the charge pump proportional current */ if (tune->set_crport_mpll_charge_pump) { samsung_exynos_cal_cr_write(usbphy_info, 0x30, 0xC0); } if (tune->enable_fixed_rxeq_mode) { samsung_exynos_cal_usb3phy_tune_fix_rxeq( usbphy_info); } set_ss_tx_impedance(usbphy_info); } } } void samsung_exynos_cal_usb3phy_disable(struct exynos_usbphy_info *usbphy_info) { void __iomem *regs_base = usbphy_info->regs_base; u32 version = usbphy_info->version; u32 phyutmi; u32 phyclkrst; phyclkrst = readl(regs_base + EXYNOS_USBCON_PHYCLKRST); phyclkrst |= PHYCLKRST_EN_UTMISUSPEND; phyclkrst |= PHYCLKRST_COMMONONN; phyclkrst |= PHYCLKRST_RETENABLEN; phyclkrst &= ~PHYCLKRST_REF_SSP_EN; phyclkrst &= ~PHYCLKRST_SSC_EN; /* Select Reference clock source path */ phyclkrst &= ~PHYCLKRST_REFCLKSEL_MASK; phyclkrst |= PHYCLKRST_REFCLKSEL(usbphy_info->refsel); /* Select ref clk */ phyclkrst &= ~PHYCLKRST_FSEL_MASK; phyclkrst |= PHYCLKRST_FSEL(usbphy_info->refclk & 0x3f); writel(phyclkrst, regs_base + EXYNOS_USBCON_PHYCLKRST); phyutmi = readl(regs_base + EXYNOS_USBCON_PHYUTMI); phyutmi &= ~PHYUTMI_IDPULLUP; phyutmi &= ~PHYUTMI_DRVVBUS; phyutmi |= PHYUTMI_FORCESUSPEND; phyutmi |= PHYUTMI_FORCESLEEP; if (usbphy_info->not_used_vbus_pad) { phyutmi &= ~PHYUTMI_VBUSVLDEXTSEL; phyutmi &= ~PHYUTMI_VBUSVLDEXT; } writel(phyutmi, regs_base + EXYNOS_USBCON_PHYUTMI); if ((EXYNOS_USBCON_VER_01_0_0 <= version) && (version <= EXYNOS_USBCON_VER_01_MAX)) { exynos_cal_ss_power_down(usbphy_info, 0); } else if (version >= EXYNOS_USBCON_VER_02_0_0 && version <= EXYNOS_USBCON_VER_02_MAX) { exynos_cal_hs_power_down(usbphy_info, 0); } /* Clear VBUSVALID signal if VBUS pad is not used */ if (usbphy_info->not_used_vbus_pad) { u32 linksystem; linksystem = readl(regs_base + EXYNOS_USBCON_LINKSYSTEM); linksystem &= ~LINKSYSTEM_FORCE_BVALID; linksystem &= ~LINKSYSTEM_FORCE_VBUSVALID; writel(linksystem, regs_base + EXYNOS_USBCON_LINKSYSTEM); } /* Set force q-channel */ if ((version & 0xf) >= 0x01) exynos_cal_usbphy_q_ch(regs_base, 0); } void samsung_exynos_cal_usb3phy_config_host_mode( struct exynos_usbphy_info *usbphy_info) { void __iomem *regs_base = usbphy_info->regs_base; u32 phyutmi; phyutmi = readl(regs_base + EXYNOS_USBCON_PHYUTMI); phyutmi |= PHYUTMI_DMPULLDOWN; phyutmi |= PHYUTMI_DPPULLDOWN; phyutmi &= ~PHYUTMI_VBUSVLDEXTSEL; phyutmi &= ~PHYUTMI_VBUSVLDEXT; writel(phyutmi, regs_base + EXYNOS_USBCON_PHYUTMI); } void samsung_exynos_cal_usb3phy_enable_dp_pullup( struct exynos_usbphy_info *usbphy_info) { void __iomem *regs_base = usbphy_info->regs_base; u32 phyutmi; phyutmi = readl(regs_base + EXYNOS_USBCON_PHYUTMI); phyutmi |= PHYUTMI_VBUSVLDEXT; writel(phyutmi, regs_base + EXYNOS_USBCON_PHYUTMI); } void samsung_exynos_cal_usb3phy_disable_dp_pullup( struct exynos_usbphy_info *usbphy_info) { void __iomem *regs_base = usbphy_info->regs_base; u32 phyutmi; phyutmi = readl(regs_base + EXYNOS_USBCON_PHYUTMI); phyutmi &= ~PHYUTMI_VBUSVLDEXT; writel(phyutmi, regs_base + EXYNOS_USBCON_PHYUTMI); } void samsung_exynos_cal_usb3phy_tune_each( struct exynos_usbphy_info *usbphy_info, enum exynos_usbphy_tune_para para, int val) { void __iomem *regs_base = usbphy_info->regs_base; u32 reg; #if defined(USB_MUX_UTMI_ENABLE) /* UE_TASK: for utmi 2nd port test : will be removed */ if (usbphy_info->regs_base_2nd && usbphy_info->used_phy_port == 1) regs_base = usbphy_info->regs_base_2nd; #endif if (para < 0x10000) { struct exynos_usbphy_hs_tune *tune = usbphy_info->hs_tune; reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM0); switch ((int) para) { case USBPHY_TUNE_HS_COMPDIS: reg &= ~PHYPARAM0_COMPDISTUNE_MASK; reg |= PHYPARAM0_COMPDISTUNE(val); if (tune) tune->compdis = val; break; case USBPHY_TUNE_HS_OTG: reg &= ~PHYPARAM0_OTGTUNE_MASK; reg |= PHYPARAM0_OTGTUNE(val); if (tune) tune->otg = val; break; case USBPHY_TUNE_HS_SQRX: reg &= ~PHYPARAM0_SQRXTUNE_MASK; reg |= PHYPARAM0_SQRXTUNE(val); if (tune) tune->rx_sqrx = val; break; case USBPHY_TUNE_HS_TXFSLS: reg &= ~PHYPARAM0_TXFSLSTUNE_MASK; reg |= PHYPARAM0_TXFSLSTUNE(val); if (tune) tune->tx_fsls = val; break; case USBPHY_TUNE_HS_TXHSXV: reg &= ~PHYPARAM0_TXHSXVTUNE_MASK; reg |= PHYPARAM0_TXHSXVTUNE(val); if (tune) tune->tx_hsxv = val; break; case USBPHY_TUNE_HS_TXPREEMP: reg &= ~PHYPARAM0_TXPREEMPAMPTUNE_MASK; reg |= PHYPARAM0_TXPREEMPAMPTUNE(val); if (tune) tune->tx_pre_emp = val; break; case USBPHY_TUNE_HS_TXPREEMP_PLUS: if (val) reg |= PHYPARAM0_TXPREEMPPULSETUNE; else reg &= ~PHYPARAM0_TXPREEMPPULSETUNE; if (tune) tune->tx_pre_emp_plus = val & 0x1; break; case USBPHY_TUNE_HS_TXRES: reg &= ~PHYPARAM0_TXRESTUNE_MASK; reg |= PHYPARAM0_TXRESTUNE(val); if (tune) tune->tx_res = val; break; case USBPHY_TUNE_HS_TXRISE: reg &= ~PHYPARAM0_TXRISETUNE_MASK; reg |= PHYPARAM0_TXRISETUNE(val); if (tune) tune->tx_rise = val; break; case USBPHY_TUNE_HS_TXVREF: reg &= ~PHYPARAM0_TXVREFTUNE_MASK; reg |= PHYPARAM0_TXVREFTUNE(val); if (tune) tune->tx_vref = val; break; } writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM0); } else { struct exynos_usbphy_ss_tune *tune = usbphy_info->ss_tune; if (usbphy_info->used_phy_port != -1) { if (usbphy_info->used_phy_port == 0) regs_base = usbphy_info->regs_base; else regs_base = usbphy_info->regs_base_2nd; } switch ((int) para) { case USBPHY_TUNE_SS_FIX_EQ: samsung_exynos_cal_usb3phy_tune_adaptive_eq(usbphy_info, val); if (tune) tune->enable_fixed_rxeq_mode = val & 0x1; break; case USBPHY_TUNE_SS_RX_EQ: samsung_exynos_cal_usb3phy_tune_chg_rxeq(usbphy_info, val); if (tune) tune->fix_rxeq_value = val & 0xf; break; case USBPHY_TUNE_SS_TX_BOOST: reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM2); reg &= ~PHYPARAM2_TX_VBOOST_LVL_MASK; reg |= PHYPARAM2_TX_VBOOST_LVL(val); writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM2); if (tune) tune->tx_boost_level = val; break; case USBPHY_TUNE_SS_TX_SWING: #if !defined(USB_SS_TX_TUNE_PCS) reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM1); reg &= ~PHYPARAM1_PCS_TXSWING_FULL_MASK; reg |= PHYPARAM1_PCS_TXSWING_FULL(val); writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM1); #else reg = samsung_exynos_cal_cr_read(usbphy_info, 0x1002); reg &= ~0x7f; reg |= val; samsung_exynos_cal_cr_write(usbphy_info, 0x1002, 0x4000 | reg); #endif if (tune) tune->tx_swing_full = val; break; case USBPHY_TUNE_SS_TX_DEEMPHASIS: #if !defined(USB_SS_TX_TUNE_PCS) reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM1); reg &= ~PHYPARAM1_PCS_TXDEEMPH_3P5DB_MASK; reg |= PHYPARAM1_PCS_TXDEEMPH_3P5DB(val); writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM1); #else reg = samsung_exynos_cal_cr_read(usbphy_info, 0x1002); reg &= ~(0x3f << 7); reg |= (val & 0x3f) << 7; samsung_exynos_cal_cr_write(usbphy_info, 0x1002, 0x4000 | reg); #endif if (tune) tune->tx_deemphasis_3p5db = val; break; } } } void samsung_exynos_cal_usb3phy_hs_tune_extract( struct exynos_usbphy_info *usbphy_info) { struct exynos_usbphy_hs_tune *hs_tune; u32 reg; hs_tune = usbphy_info->hs_tune; if (!hs_tune) return; reg = readl(usbphy_info->regs_base + EXYNOS_USBCON_PHYPARAM0); hs_tune->tx_vref = PHYPARAM0_TXVREFTUNE_EXT(reg); hs_tune->tx_rise = PHYPARAM0_TXRISETUNE_EXT(reg); hs_tune->tx_res = PHYPARAM0_TXRESTUNE_EXT(reg); hs_tune->tx_pre_emp_plus = PHYPARAM0_TXPREEMPPULSETUNE_EXT(reg); hs_tune->tx_pre_emp = PHYPARAM0_TXPREEMPAMPTUNE_EXT(reg); hs_tune->tx_hsxv = PHYPARAM0_TXHSXVTUNE_EXT(reg); hs_tune->tx_fsls = PHYPARAM0_TXFSLSTUNE_EXT(reg); hs_tune->rx_sqrx = PHYPARAM0_SQRXTUNE_EXT(reg); hs_tune->otg = PHYPARAM0_OTGTUNE_EXT(reg); hs_tune->compdis = PHYPARAM0_COMPDISTUNE_EXT(reg); } void samsung_exynos_cal_usb3phy_tune_dev(struct exynos_usbphy_info *usbphy_info) { void __iomem *regs_base = usbphy_info->regs_base; u32 reg; #if defined(USB_MUX_UTMI_ENABLE) /* UE_TASK: for utmi 2nd port test : will be removed */ if (usbphy_info->regs_base_2nd && usbphy_info->used_phy_port == 1) regs_base = usbphy_info->regs_base_2nd; #endif /* Set the LINK Version Control and Frame Adjust Value */ reg = readl(regs_base + EXYNOS_USBCON_LINKSYSTEM); reg &= ~LINKSYSTEM_FLADJ_MASK; reg |= LINKSYSTEM_FLADJ(0x20); reg |= LINKSYSTEM_XHCI_VERSION_CONTROL; writel(reg, regs_base + EXYNOS_USBCON_LINKSYSTEM); /* Tuning the HS Block of phy */ if (usbphy_info->hs_tune) { struct exynos_usbphy_hs_tune *tune = usbphy_info->hs_tune; /* Set tune value for 2.0(HS/FS) function */ reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM0); /* TX VREF TUNE */ reg &= ~PHYPARAM0_TXVREFTUNE_MASK; reg |= PHYPARAM0_TXVREFTUNE(tune->tx_vref); /* TX RISE TUNE */ reg &= ~PHYPARAM0_TXRISETUNE_MASK; reg |= PHYPARAM0_TXRISETUNE(tune->tx_rise); /* TX RES TUNE */ reg &= ~PHYPARAM0_TXRESTUNE_MASK; reg |= PHYPARAM0_TXRESTUNE(tune->tx_res); /* TX PRE EMPHASIS PLUS */ if (tune->tx_pre_emp_plus) reg |= PHYPARAM0_TXPREEMPPULSETUNE; else reg &= ~PHYPARAM0_TXPREEMPPULSETUNE; /* TX PRE EMPHASIS */ reg &= ~PHYPARAM0_TXPREEMPAMPTUNE_MASK; reg |= PHYPARAM0_TXPREEMPAMPTUNE(tune->tx_pre_emp); /* TX HS XV TUNE */ reg &= ~PHYPARAM0_TXHSXVTUNE_MASK; reg |= PHYPARAM0_TXHSXVTUNE(tune->tx_hsxv); /* TX FSLS TUNE */ reg &= ~PHYPARAM0_TXFSLSTUNE_MASK; reg |= PHYPARAM0_TXFSLSTUNE(tune->tx_fsls); /* RX SQ TUNE */ reg &= ~PHYPARAM0_SQRXTUNE_MASK; reg |= PHYPARAM0_SQRXTUNE(tune->rx_sqrx); /* OTG TUNE */ reg &= ~PHYPARAM0_OTGTUNE_MASK; reg |= PHYPARAM0_OTGTUNE(tune->otg); /* COM DIS TUNE */ reg &= ~PHYPARAM0_COMPDISTUNE_MASK; reg |= PHYPARAM0_COMPDISTUNE(tune->compdis); writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM0); } /* Tuning the SS Block of phy */ if (usbphy_info->ss_tune) { struct exynos_usbphy_ss_tune *tune = usbphy_info->ss_tune; if (usbphy_info->used_phy_port != -1) { if (usbphy_info->used_phy_port == 0) regs_base = usbphy_info->regs_base; else regs_base = usbphy_info->regs_base_2nd; } #if !defined(USB_SS_TX_TUNE_PCS) /* Set the PHY Signal Quality Tuning Value */ reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM1); /* TX SWING FULL */ reg &= ~PHYPARAM1_PCS_TXSWING_FULL_MASK; reg |= PHYPARAM1_PCS_TXSWING_FULL(tune->tx_swing_full); /* TX DE EMPHASIS 3.5 dB */ reg &= ~PHYPARAM1_PCS_TXDEEMPH_3P5DB_MASK; reg |= PHYPARAM1_PCS_TXDEEMPH_3P5DB( tune->tx_deemphasis_3p5db); writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM1); #endif /* Set vboost value for eye diagram */ reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM2); /* TX VBOOST Value */ reg &= ~PHYPARAM2_TX_VBOOST_LVL_MASK; reg |= PHYPARAM2_TX_VBOOST_LVL(tune->tx_boost_level); /* LOS BIAS */ reg &= ~PHYPARAM2_LOS_BIAS_MASK; reg |= PHYPARAM2_LOS_BIAS(tune->los_bias); writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM2); /* * Set pcs_rx_los_mask_val for 14nm PHY to mask the abnormal * LFPS and glitches */ reg = readl(regs_base + EXYNOS_USBCON_PHYPCSVAL); reg &= ~PHYPCSVAL_PCS_RX_LOS_MASK_VAL_MASK; reg |= PHYPCSVAL_PCS_RX_LOS_MASK_VAL(tune->los_mask_val); writel(reg, regs_base + EXYNOS_USBCON_PHYPCSVAL); } } void samsung_exynos_cal_usb3phy_tune_host( struct exynos_usbphy_info *usbphy_info) { void __iomem *regs_base = usbphy_info->regs_base; u32 reg; #if defined(USB_MUX_UTMI_ENABLE) /* UE_TASK: for utmi 2nd port test : will be removed */ if (usbphy_info->regs_base_2nd && usbphy_info->used_phy_port == 1) regs_base = usbphy_info->regs_base_2nd; #endif /* Set the LINK Version Control and Frame Adjust Value */ reg = readl(regs_base + EXYNOS_USBCON_LINKSYSTEM); reg &= ~LINKSYSTEM_FLADJ_MASK; reg |= LINKSYSTEM_FLADJ(0x20); reg |= LINKSYSTEM_XHCI_VERSION_CONTROL; writel(reg, regs_base + EXYNOS_USBCON_LINKSYSTEM); /* Tuning the HS Block of phy */ if (usbphy_info->hs_tune) { struct exynos_usbphy_hs_tune *tune = usbphy_info->hs_tune; /* Set tune value for 2.0(HS/FS) function */ reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM0); /* TX VREF TUNE */ reg &= ~PHYPARAM0_TXVREFTUNE_MASK; reg |= PHYPARAM0_TXVREFTUNE(tune->tx_vref); /* TX RISE TUNE */ reg &= ~PHYPARAM0_TXRISETUNE_MASK; reg |= PHYPARAM0_TXRISETUNE(tune->tx_rise); /* TX RES TUNE */ reg &= ~PHYPARAM0_TXRESTUNE_MASK; reg |= PHYPARAM0_TXRESTUNE(tune->tx_res); /* TX PRE EMPHASIS PLUS */ if (tune->tx_pre_emp_plus) reg |= PHYPARAM0_TXPREEMPPULSETUNE; else reg &= ~PHYPARAM0_TXPREEMPPULSETUNE; /* TX PRE EMPHASIS */ reg &= ~PHYPARAM0_TXPREEMPAMPTUNE_MASK; reg |= PHYPARAM0_TXPREEMPAMPTUNE(tune->tx_pre_emp); /* TX HS XV TUNE */ reg &= ~PHYPARAM0_TXHSXVTUNE_MASK; reg |= PHYPARAM0_TXHSXVTUNE(tune->tx_hsxv); /* TX FSLS TUNE */ reg &= ~PHYPARAM0_TXFSLSTUNE_MASK; reg |= PHYPARAM0_TXFSLSTUNE(tune->tx_fsls); /* RX SQ TUNE */ reg &= ~PHYPARAM0_SQRXTUNE_MASK; reg |= PHYPARAM0_SQRXTUNE(tune->rx_sqrx); /* OTG TUNE */ reg &= ~PHYPARAM0_OTGTUNE_MASK; reg |= PHYPARAM0_OTGTUNE(tune->otg); /* COM DIS TUNE */ reg &= ~PHYPARAM0_COMPDISTUNE_MASK; reg |= PHYPARAM0_COMPDISTUNE(tune->compdis); writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM0); } /* Tuning the SS Block of phy */ if (usbphy_info->ss_tune) { struct exynos_usbphy_ss_tune *tune = usbphy_info->ss_tune; if (usbphy_info->used_phy_port != -1) { if (usbphy_info->used_phy_port == 0) regs_base = usbphy_info->regs_base; else regs_base = usbphy_info->regs_base_2nd; } #if !defined(USB_SS_TX_TUNE_PCS) /* Set the PHY Signal Quality Tuning Value */ reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM1); /* TX SWING FULL */ reg &= ~PHYPARAM1_PCS_TXSWING_FULL_MASK; reg |= PHYPARAM1_PCS_TXSWING_FULL(tune->tx_swing_full); /* TX DE EMPHASIS 3.5 dB */ reg &= ~PHYPARAM1_PCS_TXDEEMPH_3P5DB_MASK; reg |= PHYPARAM1_PCS_TXDEEMPH_3P5DB( tune->tx_deemphasis_3p5db); writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM1); #endif /* Set vboost value for eye diagram */ reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM2); /* TX VBOOST Value */ reg &= ~PHYPARAM2_TX_VBOOST_LVL_MASK; reg |= PHYPARAM2_TX_VBOOST_LVL(tune->tx_boost_level); /* LOS BIAS */ reg &= ~PHYPARAM2_LOS_BIAS_MASK; reg |= PHYPARAM2_LOS_BIAS(tune->los_bias); writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM2); /* * Set pcs_rx_los_mask_val for 14nm PHY to mask the abnormal * LFPS and glitches */ reg = readl(regs_base + EXYNOS_USBCON_PHYPCSVAL); reg &= ~PHYPCSVAL_PCS_RX_LOS_MASK_VAL_MASK; reg |= PHYPCSVAL_PCS_RX_LOS_MASK_VAL(tune->los_mask_val); writel(reg, regs_base + EXYNOS_USBCON_PHYPCSVAL); } }