/* * 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. */ #ifndef __EXCITE__ #include #include #endif #include #include "phy-samsung-usb-cal.h" #include "phy-samsung-usb3-cal.h" 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 *regs_base = usbphy_info->regs_base; u32 phyreg0; u32 phyreg1; u32 loop; u32 loop_cnt; /* Clear CR port register */ phyreg0 = readl(regs_base + EXYNOS_USBCON_PHYREG0); phyreg0 &= ~(0xfffff); writel(phyreg0, regs_base + EXYNOS_USBCON_PHYREG0); /* Set Data for cr port */ phyreg0 &= ~PHYREG0_CR_DATA_MASK; phyreg0 |= PHYREG0_CR_DATA_IN(data); writel(phyreg0, regs_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, regs_base + EXYNOS_USBCON_PHYREG0); /* Handshake */ do { phyreg1 = readl(regs_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_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 phyparam0; u32 phyreg0; u32 phypipe; u32 linkport; /* Set force q-channel */ if ((version & 0xf) >= 0x01) { u32 phy_resume; /* 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_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); } /* 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)) { if (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(regs_base + EXYNOS_USBCON_PHYPARAM0); if (usbphy_info->refsel == USBPHY_REFSEL_DIFF_PAD) phyparam0 |= PHYPARAM0_REF_USE_PAD; else phyparam0 &= ~PHYPARAM0_REF_USE_PAD; writel(phyparam0, regs_base + EXYNOS_USBCON_PHYPARAM0); if (version >= EXYNOS_USBCON_VER_01_0_1) phyreg0 = readl(regs_base + EXYNOS_USBCON_PHYREG0); switch (refclkfreq) { case USBPHY_REFCLK_DIFF_100MHZ: phyclkrst &= ~PHYCLKRST_MPLL_MULTIPLIER_MASK; phyclkrst |= PHYCLKRST_MPLL_MULTIPLIER(0x00); phyclkrst &= ~PHYCLKRST_REF_CLKDIV2; if (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: phyclkrst &= ~PHYCLKRST_MPLL_MULTIPLIER_MASK; phyclkrst |= PHYCLKRST_MPLL_MULTIPLIER(0x60); phyclkrst &= ~PHYCLKRST_REF_CLKDIV2; if (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 (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; default: break; } /* SSC Enable */ phyclkrst |= PHYCLKRST_SSC_EN; if (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(regs_base + EXYNOS_USBCON_PHYPIPE); phypipe |= PHY_CLOCK_SEL; writel(phypipe, regs_base + EXYNOS_USBCON_PHYPIPE); if (version >= EXYNOS_USBCON_VER_01_0_1) writel(phyreg0, regs_base + EXYNOS_USBCON_PHYREG0); } else if ((EXYNOS_USBCON_VER_02_0_0 <= version) && (version <= EXYNOS_USBCON_VER_02_MAX)) { u32 hsphyplltune = readl( regs_base + EXYNOS_USBCON_HSPHYPLLTUNE); if ((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 (refclkfreq == USBPHY_REFCLK_EXT_24MHZ) hsphyplltune |= HSPHYPLLTUNE_PLL_B_TUNE; else hsphyplltune &= ~HSPHYPLLTUNE_PLL_B_TUNE; hsphyplltune |= HSPHYPLLTUNE_PLL_P_TUNE(0xe); writel(hsphyplltune, regs_base + EXYNOS_USBCON_HSPHYPLLTUNE); } 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)) { u32 phytest; phytest = readl(regs_base + EXYNOS_USBCON_PHYTEST); phytest &= ~PHYTEST_POWERDOWN_HSP; phytest &= ~PHYTEST_POWERDOWN_SSP; writel(phytest, regs_base + EXYNOS_USBCON_PHYTEST); } else if (version >= EXYNOS_USBCON_VER_02_0_0 && version <= EXYNOS_USBCON_VER_02_MAX) { u32 hsphyctrl; hsphyctrl = readl(regs_base + EXYNOS_USBCON_HSPHYCTRL); hsphyctrl &= ~HSPHYCTRL_SIDDQ; hsphyctrl &= ~HSPHYCTRL_PHYSWRST; hsphyctrl &= ~HSPHYCTRL_PHYSWRSTALL; writel(hsphyctrl, regs_base + EXYNOS_USBCON_HSPHYCTRL); } udelay(500); /* 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); } /* 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 DP-Pull up if VBUS pad is not used */ if (usbphy_info->not_used_vbus_pad) { 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); /* 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); } if (EXYNOS_USBCON_VER_01_0_0 <= version && version <= EXYNOS_USBCON_VER_01_MAX) samsung_exynos_cal_usb3phy_set_cr_port(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)) { u32 phytest; phytest = readl(regs_base + EXYNOS_USBCON_PHYTEST); phytest |= PHYTEST_POWERDOWN_HSP; phytest |= PHYTEST_POWERDOWN_SSP; writel(phytest, regs_base + EXYNOS_USBCON_PHYTEST); } else if (version >= EXYNOS_USBCON_VER_02_0_0 && version <= EXYNOS_USBCON_VER_02_MAX) { u32 hsphyctrl; hsphyctrl = readl(regs_base + EXYNOS_USBCON_HSPHYCTRL); hsphyctrl |= HSPHYCTRL_SIDDQ; writel(hsphyctrl, regs_base + EXYNOS_USBCON_HSPHYCTRL); } /* 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) { u32 phy_resume; 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; writel(phy_resume, regs_base + EXYNOS_USBCON_PHYRESUME); } } 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_set_cr_port( struct exynos_usbphy_info *usbphy_info) { if (usbphy_info->ss_tune) { if (usbphy_info->ss_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 (usbphy_info->ss_tune->set_crport_mpll_charge_pump) samsung_exynos_cal_cr_write(usbphy_info, 0x30, 0xC0); } /* Set RXDET_MEAS_TIME[11:4] each reference clock */ samsung_exynos_cal_cr_write(usbphy_info, 0x1010, 0x80); } void samsung_exynos_cal_usb3phy_tune_dev(struct exynos_usbphy_info *usbphy_info) { void __iomem *regs_base = usbphy_info->regs_base; u32 linksystem; u32 phyparam0; u32 phyparam1; u32 phyparam2; u32 phypcsval; /* Set the LINK Version Control and Frame Adjust Value */ linksystem = readl(regs_base + EXYNOS_USBCON_LINKSYSTEM); linksystem &= ~LINKSYSTEM_FLADJ_MASK; linksystem |= LINKSYSTEM_FLADJ(0x20); linksystem |= LINKSYSTEM_XHCI_VERSION_CONTROL; writel(linksystem, 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 */ phyparam0 = readl(regs_base + EXYNOS_USBCON_PHYPARAM0); /* TX VREF TUNE */ phyparam0 &= ~PHYPARAM0_TXVREFTUNE_MASK; phyparam0 |= PHYPARAM0_TXVREFTUNE(tune->tx_vref); /* TX RISE TUNE */ phyparam0 &= ~PHYPARAM0_TXRISETUNE_MASK; phyparam0 |= PHYPARAM0_TXRISETUNE(tune->tx_rise); /* TX RES TUNE */ phyparam0 &= ~PHYPARAM0_TXRESTUNE_MASK; phyparam0 |= PHYPARAM0_TXRESTUNE(tune->tx_res); /* TX PRE EMPHASIS PULS */ if (tune->tx_pre_emp_puls) phyparam0 |= PHYPARAM0_TXPREEMPPULSETUNE; else phyparam0 &= ~PHYPARAM0_TXPREEMPPULSETUNE; /* TX PRE EMPHASIS */ phyparam0 &= ~PHYPARAM0_TXPREEMPAMPTUNE_MASK; phyparam0 |= PHYPARAM0_TXPREEMPAMPTUNE(tune->tx_pre_emp); /* TX HS XV TUNE */ phyparam0 &= ~PHYPARAM0_TXHSXVTUNE_MASK; phyparam0 |= PHYPARAM0_TXHSXVTUNE(tune->tx_hsxv); /* TX FSLS TUNE */ phyparam0 &= ~PHYPARAM0_TXFSLSTUNE_MASK; phyparam0 |= PHYPARAM0_TXFSLSTUNE(tune->tx_fsls); /* RX SQ TUNE */ phyparam0 &= ~PHYPARAM0_SQRXTUNE_MASK; phyparam0 |= PHYPARAM0_SQRXTUNE(tune->rx_sqrx); /* OTG TUNE */ phyparam0 &= ~PHYPARAM0_OTGTUNE_MASK; phyparam0 |= PHYPARAM0_OTGTUNE(tune->otg); /* COM DIS TUNE */ phyparam0 &= ~PHYPARAM0_COMPDISTUNE_MASK; phyparam0 |= PHYPARAM0_COMPDISTUNE(tune->compdis); writel(phyparam0, 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; /* Set the PHY Signal Quality Tuning Value */ phyparam1 = readl(regs_base + EXYNOS5_USBCON_PHYPARAM1); /* TX SWING FULL */ phyparam1 &= ~PHYPARAM1_PCS_TXSWING_FULL_MASK; phyparam1 |= PHYPARAM1_PCS_TXSWING_FULL(tune->tx_swing_full); /* TX DE EMPHASIS 3.5 dB */ phyparam1 &= ~PHYPARAM1_PCS_TXDEEMPH_3P5DB_MASK; phyparam1 |= PHYPARAM1_PCS_TXDEEMPH_3P5DB( tune->tx_deemphasis_3p5db); writel(phyparam1, regs_base + EXYNOS5_USBCON_PHYPARAM1); /* Set vboost value for eye diagram */ phyparam2 = readl(regs_base + EXYNOS_USBCON_PHYPARAM2); /* TX VBOOST Value */ phyparam2 &= ~PHYPARAM2_TX_VBOOST_LVL_MASK; phyparam2 |= PHYPARAM2_TX_VBOOST_LVL(tune->tx_boost_level); /* LOS BIAS */ phyparam2 &= ~PHYPARAM2_LOS_BIAS_MASK; phyparam2 |= PHYPARAM2_LOS_BIAS(tune->los_bias); writel(phyparam2, regs_base + EXYNOS_USBCON_PHYPARAM2); /* * Set pcs_rx_los_mask_val for 14nm PHY to mask the abnormal * LFPS and glitches */ phypcsval = readl(regs_base + EXYNOS_USBCON_PHYPCSVAL); phypcsval &= ~PHYPCSVAL_PCS_RX_LOS_MASK_VAL_MASK; phypcsval |= PHYPCSVAL_PCS_RX_LOS_MASK_VAL(tune->los_mask_val); writel(phypcsval, 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 linksystem; u32 phyparam0; u32 phyparam1; u32 phyparam2; u32 phypcsval; /* Set the LINK Version Control and Frame Adjust Value */ linksystem = readl(regs_base + EXYNOS_USBCON_LINKSYSTEM); linksystem &= ~LINKSYSTEM_FLADJ_MASK; linksystem |= LINKSYSTEM_FLADJ(0x20); linksystem |= LINKSYSTEM_XHCI_VERSION_CONTROL; writel(linksystem, 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 */ phyparam0 = readl(regs_base + EXYNOS_USBCON_PHYPARAM0); /* TX VREF TUNE */ phyparam0 &= ~PHYPARAM0_TXVREFTUNE_MASK; phyparam0 |= PHYPARAM0_TXVREFTUNE(tune->tx_vref); /* TX RISE TUNE */ phyparam0 &= ~PHYPARAM0_TXRISETUNE_MASK; phyparam0 |= PHYPARAM0_TXRISETUNE(tune->tx_rise); /* TX RES TUNE */ phyparam0 &= ~PHYPARAM0_TXRESTUNE_MASK; phyparam0 |= PHYPARAM0_TXRESTUNE(tune->tx_res); /* TX PRE EMPHASIS PULS */ if (tune->tx_pre_emp_puls) phyparam0 |= PHYPARAM0_TXPREEMPPULSETUNE; else phyparam0 &= ~PHYPARAM0_TXPREEMPPULSETUNE; /* TX PRE EMPHASIS */ phyparam0 &= ~PHYPARAM0_TXPREEMPAMPTUNE_MASK; phyparam0 |= PHYPARAM0_TXPREEMPAMPTUNE(tune->tx_pre_emp); /* TX HS XV TUNE */ phyparam0 &= ~PHYPARAM0_TXHSXVTUNE_MASK; phyparam0 |= PHYPARAM0_TXHSXVTUNE(tune->tx_hsxv); /* TX FSLS TUNE */ phyparam0 &= ~PHYPARAM0_TXFSLSTUNE_MASK; phyparam0 |= PHYPARAM0_TXFSLSTUNE(tune->tx_fsls); /* RX SQ TUNE */ phyparam0 &= ~PHYPARAM0_SQRXTUNE_MASK; phyparam0 |= PHYPARAM0_SQRXTUNE(tune->rx_sqrx); /* OTG TUNE */ phyparam0 &= ~PHYPARAM0_OTGTUNE_MASK; phyparam0 |= PHYPARAM0_OTGTUNE(tune->otg); /* COM DIS TUNE */ phyparam0 &= ~PHYPARAM0_COMPDISTUNE_MASK; phyparam0 |= PHYPARAM0_COMPDISTUNE(tune->compdis); writel(phyparam0, 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; /* Set the PHY Signal Quality Tuning Value */ phyparam1 = readl(regs_base + EXYNOS5_USBCON_PHYPARAM1); /* TX SWING FULL */ phyparam1 &= ~PHYPARAM1_PCS_TXSWING_FULL_MASK; phyparam1 |= PHYPARAM1_PCS_TXSWING_FULL(tune->tx_swing_full); /* TX DE EMPHASIS 3.5 dB */ phyparam1 &= ~PHYPARAM1_PCS_TXDEEMPH_3P5DB_MASK; phyparam1 |= PHYPARAM1_PCS_TXDEEMPH_3P5DB( tune->tx_deemphasis_3p5db); writel(phyparam1, regs_base + EXYNOS5_USBCON_PHYPARAM1); /* Set vboost value for eye diagram */ phyparam2 = readl(regs_base + EXYNOS_USBCON_PHYPARAM2); /* TX VBOOST Value */ phyparam2 &= ~PHYPARAM2_TX_VBOOST_LVL_MASK; phyparam2 |= PHYPARAM2_TX_VBOOST_LVL(tune->tx_boost_level); /* LOS BIAS */ phyparam2 &= ~PHYPARAM2_LOS_BIAS_MASK; phyparam2 |= PHYPARAM2_LOS_BIAS(tune->los_bias); writel(phyparam2, regs_base + EXYNOS_USBCON_PHYPARAM2); /* * Set pcs_rx_los_mask_val for 14nm PHY to mask the abnormal * LFPS and glitches */ phypcsval = readl(regs_base + EXYNOS_USBCON_PHYPCSVAL); phypcsval &= ~PHYPCSVAL_PCS_RX_LOS_MASK_VAL_MASK; phypcsval |= PHYPCSVAL_PCS_RX_LOS_MASK_VAL(tune->los_mask_val); writel(phypcsval, regs_base + EXYNOS_USBCON_PHYPCSVAL); } }