/* * Samsung EXYNOS SoC series USB DRD PHY DebugFS file * * Phy provider for USB 3.0 DRD controller on Exynos SoC series * * Copyright (C) 2016 Samsung Electronics Co., Ltd. * Author: Kyounghye Yun * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "phy-exynos-usbdrd.h" #include "phy-samsung-usb3-cal.h" #include "phy-samsung-usb3-cal-combo.h" #include "phy-exynos-debug.h" struct exynos_debugfs_prvdata *prvdata; /* PHY Control register set of SOC which combo phy is applied in */ static const struct debugfs_reg32 exynos_usb3drd_phycon_regs[] = { dump_register(CTRLVER), dump_register(LINKCTRL), dump_register(PHYCON_LINKPORT), dump_register(LINK_DEBUG_L), dump_register(LINK_DEBUG_H), dump_register(LTSTATE_HIS), dump_register(CLKRSTCTRL), dump_register(PWRCTL), dump_register(SSPPLLCTL), dump_register(SECPMACTL), dump_register(UTMICTRL), dump_register(HSPCTRL), dump_register(HSPPARACON), dump_register(HSPTEST), dump_register(HSPPLLTUNE), dump_register(REWA_CTRL), dump_register(HSREWA_INTR), dump_register(HSREWA_CTRL), dump_register(HSREWA_REFTO), dump_register(HSREWA_HSTK), dump_register(HSREWA_CNT), dump_register(HSREWA_INT1_EVNT), dump_register(HSREWA_INT1_EVNT_MSK), }; static const struct debugfs_reg32 exynos_usb3drd_regs[] = { dump_register(LINKSYSTEM), dump_register(PHYUTMI), dump_register(PHYCLKRST), dump_register(PHYREG0), dump_register(PHYPARAM0), dump_register(PHYPARAM1), dump_register(PHYTEST), dump_register(PHYRESUME), dump_register(PHYPCSVAL), dump_register(LINKPORT), dump_register(PHYPARAM2), }; static const struct debugfs_reg32 exynos_usb2drd_regs[] = { dump_register(LINKSYSTEM), dump_register(PHYUTMI), dump_register(PHYCLKRST), dump_register(PHYPARAM0), dump_register(PHYPOWERDOWN), dump_register(PHYRESUME), dump_register(LINKPORT), dump_register(HSPHYCTRL), dump_register(HSPHYPLLTUNE), }; /* PHY Control register set of SOC which combo phy is applied in */ static const struct debugfs_regmap32 exynos_usb3drd_phycon_regmap[] = { dump_regmap_mask(CTRLVER, CTRL_VER, 0), dump_regmap(LINKCTRL, FORCE_RXELECIDLE, 18), dump_regmap(LINKCTRL, FORCE_PHYSTATUS, 17), dump_regmap(LINKCTRL, FORCE_PIPE_EN, 16), dump_regmap(LINKCTRL, DIS_BUSPEND_QACT, 13), dump_regmap(LINKCTRL, DIS_LINKGATE_QACT, 12), dump_regmap(LINKCTRL, DIS_ID0_QACT, 11), dump_regmap(LINKCTRL, DIS_VBUSVALID_QACT, 10), dump_regmap(LINKCTRL, DIS_BVALID_QACT, 9), dump_regmap(LINKCTRL, FORCE_QACT, 8), dump_regmap_mask(LINKCTRL, BUS_FILTER_BYPASS, 4), dump_regmap(LINKCTRL, HOST_SYSTEM_ERR, 2), dump_regmap(LINKCTRL, LINK_PME, 1), dump_regmap(LINKCTRL, PME_GENERATION, 0), dump_regmap_mask(PHYCON_LINKPORT, HOST_NUM_U3, 16), dump_regmap_mask(PHYCON_LINKPORT, HOST_NUM_U2, 12), dump_regmap(PHYCON_LINKPORT, HOST_U3_PORT_DISABLE, 9), dump_regmap(PHYCON_LINKPORT, HOST_U2_PORT_DISABLE, 8), dump_regmap(PHYCON_LINKPORT, HOST_PORT_POWER_CON_PRESENT, 6), dump_regmap(PHYCON_LINKPORT, HUB_PORT_OVERCURRENT_U3, 5), dump_regmap(PHYCON_LINKPORT, HUB_PORT_OVERCURRENT_U2, 4), dump_regmap(PHYCON_LINKPORT, HUB_PORT_OVERCURRENT_SET_U3, 3), dump_regmap(PHYCON_LINKPORT, HUB_PORT_OVERCURRENT_SET_U2, 2), dump_regmap(PHYCON_LINKPORT, HUB_PERM_ATTACH_U3, 1), dump_regmap(PHYCON_LINKPORT, HUB_PERM_ATTACH_U2, 0), dump_regmap_mask(LINK_DEBUG_L, DEBUG_L, 0), dump_regmap_mask(LINK_DEBUG_H, DEBUG_H, 0), dump_regmap(LTSTATE_HIS, LINKTRN_DONE, 31), dump_regmap_mask(LTSTATE_HIS, LTSTATE_HIS4, 16), dump_regmap_mask(LTSTATE_HIS, LTSTATE_HIS3, 12), dump_regmap_mask(LTSTATE_HIS, LTSTATE_HIS2, 8), dump_regmap_mask(LTSTATE_HIS, LTSTATE_HIS1, 4), dump_regmap_mask(LTSTATE_HIS, LTSTATE_HIS0, 0), dump_regmap(CLKRSTCTRL, USBAUDIO_CLK_GATE_EN, 9), dump_regmap(CLKRSTCTRL, USBAUDIO_CLK_SEL, 8), dump_regmap(CLKRSTCTRL, LINK_PCLK_SEL, 7), dump_regmap(CLKRSTCTRL, REFCLKSEL, 4), dump_regmap(CLKRSTCTRL, PHY_SW_RST, 3), dump_regmap(CLKRSTCTRL, PHY_RESET_SEL, 2), dump_regmap(CLKRSTCTRL, PORTRESET, 1), dump_regmap(CLKRSTCTRL, LINK_SW_RST, 0), dump_regmap(PWRCTL, FORCE_POWERDOWN, 2), dump_regmap_mask(SSPPLLCTL, FSEL, 0), dump_regmap_mask(SECPMACTL, PMA_PLL_REF_CLK_SEL, 10), dump_regmap_mask(SECPMACTL, PMA_REF_FREQ_SEL, 8), dump_regmap(SECPMACTL, PMA_LOW_PWR, 4), dump_regmap(SECPMACTL, PMA_TRSV_SW_RST, 3), dump_regmap(SECPMACTL, PMA_CMN_SW_RST, 2), dump_regmap(SECPMACTL, PMA_INIT_SW_RST, 1), dump_regmap(SECPMACTL, PMA_APB_SW_RST, 0), dump_regmap(UTMICTRL, OPMODE_EN, 8), dump_regmap_mask(UTMICTRL, FORCE_OPMODE, 6), dump_regmap(UTMICTRL, FORCE_VBUSVALID, 5), dump_regmap(UTMICTRL, FORCE_BVALID, 4), dump_regmap(UTMICTRL, FORCE_DPPULLDOWN, 3), dump_regmap(UTMICTRL, FORCE_DMPULLDOWN, 2), dump_regmap(UTMICTRL, FORCE_SUSPEND, 1), dump_regmap(UTMICTRL, FORCE_SLEEP, 0), dump_regmap(HSPCTRL, AUTORSM_ENB, 29), dump_regmap(HSPCTRL, RETENABLE_EN, 28), dump_regmap(HSPCTRL, FSLS_SPEED_SEL, 25), dump_regmap(HSPCTRL, FSV_OUT_EN, 24), dump_regmap(HSPCTRL, HS_XCVR_EXT_CTL, 22), dump_regmap(HSPCTRL, HS_RXDAT, 21), dump_regmap(HSPCTRL, HS_SQUELCH, 20), dump_regmap(HSPCTRL, FSVMINUS, 17), dump_regmap(HSPCTRL, FSVPLUS, 16), dump_regmap(HSPCTRL, VBUSVLDEXTSEL, 13), dump_regmap(HSPCTRL, VBUSVLDEXT, 12), dump_regmap(HSPCTRL, EN_UTMISUSPEND, 9), dump_regmap(HSPCTRL, COMMONONN, 8), dump_regmap(HSPCTRL, VATESTENB, 6), dump_regmap(HSPCTRL, CHGDET, 5), dump_regmap(HSPCTRL, VDATSRCENB, 4), dump_regmap(HSPCTRL, VDATDETENB, 3), dump_regmap(HSPCTRL, CHRGSEL, 2), dump_regmap(HSPCTRL, ACAENB, 1), dump_regmap(HSPCTRL, DEDENB, 0), dump_regmap_mask(HSPPARACON, TXVREFTUNE, 28), dump_regmap_mask(HSPPARACON, TXRISETUNE, 24), dump_regmap_mask(HSPPARACON, TXRESTUNE, 21), dump_regmap(HSPPARACON, TXPREEMPPULSETUNE, 20), dump_regmap_mask(HSPPARACON, TXPREEMPAMPTUNE, 18), dump_regmap_mask(HSPPARACON, TXHSXVTUNE, 16), dump_regmap_mask(HSPPARACON, TXFSLSTUNE, 12), dump_regmap_mask(HSPPARACON, SQRXTUNE, 8), dump_regmap_mask(HSPPARACON, OTGTUNE, 4), dump_regmap_mask(HSPPARACON, COMPDISTUNE, 0), dump_regmap(HSPTEST, SIDDQ_PORT0, 24), dump_regmap_mask(HSPTEST, LINESTATE_PORT0, 20), dump_regmap_mask(HSPTEST, TESTDATAOUT_PORT0, 16), dump_regmap(HSPTEST, TESTCLK_PORT0, 13), dump_regmap(HSPTEST, TESTDATAOUTSEL_PORT0, 12), dump_regmap_mask(HSPTEST, TESTADDR_PORT0, 8), dump_regmap_mask(HSPTEST, TESTDATAIN_PORT0, 0), dump_regmap(HSPPLLTUNE, PLLBTUNE, 8), dump_regmap_mask(HSPPLLTUNE, PLLITUNE, 4), dump_regmap_mask(HSPPLLTUNE, PLLPTUNE, 0), dump_regmap(REWA_CTRL, HSREWA_EN, 0), dump_regmap_mask(HSREWA_INTR, WAKEUP_MASK, 12), dump_regmap_mask(HSREWA_INTR, TIMEOUT_INTR_MASK, 8), dump_regmap_mask(HSREWA_INTR, EVENT_INT_MASK, 4), dump_regmap_mask(HSREWA_INTR, WAKEUP_INTR_MASK, 0), dump_regmap(HSREWA_CTRL, DIG_BYPASS_CON_EN, 28), dump_regmap(HSREWA_CTRL, DPDM_MONITOR_SEL, 24), dump_regmap(HSREWA_CTRL, HS_LINK_READY, 20), dump_regmap(HSREWA_CTRL, HS_SYS_VALID, 16), dump_regmap(HSREWA_CTRL, HS_REWA_ERROR, 4), dump_regmap(HSREWA_CTRL, HS_REWA_DONE, 0), dump_regmap_mask(HSREWA_REFTO, HOST_K_TIMEOUT, 0), dump_regmap_mask(HSREWA_HSTK, HOST_K_DELAY, 0), dump_regmap_mask(HSREWA_CNT, WAKEUP_CNT, 0), dump_regmap(HSREWA_INT1_EVNT, ERR_SUS, 18), dump_regmap(HSREWA_INT1_EVNT, ERR_DEV_K, 17), dump_regmap(HSREWA_INT1_EVNT, DISCON, 16), dump_regmap(HSREWA_INT1_EVNT, BYPASS_DIS, 2), dump_regmap(HSREWA_INT1_EVNT, RET_DIS, 1), dump_regmap(HSREWA_INT1_EVNT, RET_EN, 0), dump_regmap(HSREWA_INT1_EVNT_MSK, ERR_SUS_MASK, 18), dump_regmap(HSREWA_INT1_EVNT_MSK, ERR_DEV_K_MASK, 17), dump_regmap(HSREWA_INT1_EVNT_MSK, DISCON_MASK, 16), dump_regmap(HSREWA_INT1_EVNT_MSK, BYPASS_DIS_MASK, 2), dump_regmap(HSREWA_INT1_EVNT_MSK, RET_DIS_MASK, 1), dump_regmap(HSREWA_INT1_EVNT_MSK, RET_EN_MASK, 0), }; static const struct debugfs_regmap32 exynos_usb2drd_regmap[] = { dump_regmap(LINKSYSTEM, HOST_SYSTEM_ERR, 31), dump_regmap(LINKSYSTEM, PHY_POWER_DOWN, 30), dump_regmap(LINKSYSTEM, PHY_SW_RESET, 29), dump_regmap(LINKSYSTEM, LINK_SW_RESET, 28), dump_regmap(LINKSYSTEM, XHCI_VERSION_CONTROL, 27), dump_regmap(LINKSYSTEM, FORCE_VBUSVALID, 8), dump_regmap(LINKSYSTEM, FORCE_BVALID, 7), dump_regmap_mask(LINKSYSTEM, FLADJ, 1), dump_regmap(PHYUTMI, UTMI_SUSPEND_COM_N, 12), dump_regmap(PHYUTMI, UTMI_L1_SUSPEND_COM_N, 11), dump_regmap(PHYUTMI, VBUSVLDEXTSEL, 10), dump_regmap(PHYUTMI, VBUSVLDEXT, 9), dump_regmap(PHYUTMI, TXBITSTUFFENH, 8), dump_regmap(PHYUTMI, TXBITSTUFFEN, 7), dump_regmap(PHYUTMI, OTGDISABLE, 6), dump_regmap(PHYUTMI, IDPULLUP, 5), dump_regmap(PHYUTMI, DRVVBUS, 4), dump_regmap(PHYUTMI, DPPULLDOWN, 3), dump_regmap(PHYUTMI, DMPULLDOWN, 2), dump_regmap(PHYUTMI, FORCESUSPEND, 1), dump_regmap(PHYUTMI, FORCESLEEP, 0), dump_regmap(PHYCLKRST, EN_UTMISUSPEND, 31), dump_regmap_mask(PHYCLKRST, SSC_REFCLKSEL, 23), dump_regmap_mask(PHYCLKRST, SSC_RANGE, 21), dump_regmap(PHYCLKRST, SSC_EN, 20), dump_regmap(PHYCLKRST, REF_SSP_EN, 19), dump_regmap(PHYCLKRST, REF_CLKDIV2, 18), dump_regmap_mask(PHYCLKRST, MPLL_MULTIPLIER, 11), dump_regmap_mask(PHYCLKRST, FSEL, 5), dump_regmap(PHYCLKRST, RETENABLEN, 4), dump_regmap_mask(PHYCLKRST, REFCLKSEL, 2), dump_regmap(PHYCLKRST, PORTRESET, 1), dump_regmap(PHYCLKRST, COMMONONN, 0), dump_regmap_mask(PHYPARAM0, TXVREFTUNE, 22), dump_regmap_mask(PHYPARAM0, TXRISETUNE, 20), dump_regmap_mask(PHYPARAM0, TXRESTUNE, 18), dump_regmap(PHYPARAM0, TXPREEMPPULSETUNE, 17), dump_regmap_mask(PHYPARAM0, TXPREEMPAMPTUNE, 15), dump_regmap_mask(PHYPARAM0, TXHSXVTUNE, 13), dump_regmap_mask(PHYPARAM0, TXFSLSTUNE, 9), dump_regmap_mask(PHYPARAM0, SQRXTUNE, 6), dump_regmap_mask(PHYPARAM0, OTGTUNE, 3), dump_regmap_mask(PHYPARAM0, COMPDISTUNE, 0), dump_regmap(PHYPOWERDOWN, VATESTENB, 6), dump_regmap_mask(PHYPOWERDOWN, TEST_BURNIN, 4), dump_regmap(PHYRESUME, BYPASS_SEL, 4), dump_regmap(PHYRESUME, BYPASS_DM_EN, 3), dump_regmap(PHYRESUME, BYPASS_DP_EN, 2), dump_regmap(PHYRESUME, BYPASS_DM_DATA, 1), dump_regmap(PHYRESUME, BYPASS_DP_DATA, 0), dump_regmap_mask(LINKPORT, HOST_NUM_U2_PORT, 9), dump_regmap(LINKPORT, HOST_U2_PORT_DISABLE, 7), dump_regmap(LINKPORT, PORT_POWER_CONTROL, 6), dump_regmap(LINKPORT, HOST_PORT_OVCR_U2, 4), dump_regmap(LINKPORT, HOST_PORT_OVCR_U2_SEL, 2), dump_regmap(LINKPORT, PERM_ATTACH_U2, 0), dump_regmap(HSPHYCTRL, PHYSWRSTALL, 31), dump_regmap(HSPHYCTRL, SIDDQ, 6), dump_regmap(HSPHYCTRL, PHYSWRST, 0), dump_regmap(HSPHYPLLTUNE, PLL_B_TUNE, 6), dump_regmap_mask(HSPHYPLLTUNE, PLL_I_TUNE, 4), dump_regmap_mask(HSPHYPLLTUNE, PLL_P_TUNE, 0), }; static const struct debugfs_regmap32 exynos_usb3drd_regmap[] = { dump_regmap(LINKSYSTEM, HOST_SYSTEM_ERR, 31), dump_regmap(LINKSYSTEM, PHY_POWER_DOWN, 30), dump_regmap(LINKSYSTEM, XHCI_VERSION_CONTROL, 27), dump_regmap(LINKSYSTEM, FORCE_VBUSVALID, 8), dump_regmap(LINKSYSTEM, FORCE_BVALID, 7), dump_regmap_mask(LINKSYSTEM, FLADJ, 1), dump_regmap(PHYUTMI, VBUSVLDEXTSEL, 10), dump_regmap(PHYUTMI, VBUSVLDEXT, 9), dump_regmap(PHYUTMI, TXBITSTUFFENH, 8), dump_regmap(PHYUTMI, TXBITSTUFFEN, 7), dump_regmap(PHYUTMI, OTGDISABLE, 6), dump_regmap(PHYUTMI, IDPULLUP, 5), dump_regmap(PHYUTMI, DRVVBUS, 4), dump_regmap(PHYUTMI, DPPULLDOWN, 3), dump_regmap(PHYUTMI, DMPULLDOWN, 2), dump_regmap(PHYUTMI, FORCESUSPEND, 1), dump_regmap(PHYUTMI, FORCESLEEP, 0), dump_regmap(PHYPIPE, PHY_CLOCK_SEL, 4), dump_regmap(PHYCLKRST, EN_UTMISUSPEND, 31), dump_regmap(PHYCLKRST, SSC_EN, 20), dump_regmap(PHYCLKRST, REF_SSP_EN, 19), dump_regmap(PHYCLKRST, REF_CLKDIV2, 18), dump_regmap_mask(PHYCLKRST, MPLL_MULTIPLIER, 11), dump_regmap_mask(PHYCLKRST, FSEL, 5), dump_regmap(PHYCLKRST, RETENABLEN, 4), dump_regmap_mask(PHYCLKRST, REFCLKSEL, 2), dump_regmap(PHYCLKRST, PORTRESET, 1), dump_regmap(PHYCLKRST, COMMONONN, 0), dump_regmap_mask(PHYREG0, SSC_REFCLKSEL, 23), dump_regmap_mask(PHYREG0, SSC_RANGE, 20), dump_regmap(PHYPARAM0, REF_USE_PAD, 31), dump_regmap_mask(PHYPARAM0, REF_LOSLEVEL, 26), dump_regmap_mask(PHYPARAM0, TXVREFTUNE, 22), dump_regmap_mask(PHYPARAM0, TXRISETUNE, 20), dump_regmap_mask(PHYPARAM0, TXRESTUNE, 18), dump_regmap(PHYPARAM0, TXPREEMPPULSETUNE, 17), dump_regmap_mask(PHYPARAM0, TXPREEMPAMPTUNE, 15), dump_regmap_mask(PHYPARAM0, TXHSXVTUNE, 13), dump_regmap_mask(PHYPARAM0, TXFSLSTUNE, 9), dump_regmap_mask(PHYPARAM0, SQRXTUNE, 6), dump_regmap_mask(PHYPARAM0, OTGTUNE, 3), dump_regmap_mask(PHYPARAM0, COMPDISTUNE, 0), dump_regmap_mask(PHYPARAM1, TX0_TERM_OFFSET, 26), dump_regmap_mask(PHYPARAM1, PCS_TXSWING_FULL, 12), dump_regmap_mask(PHYPARAM1, PCS_TXDEEMPH_3P5DB, 0), dump_regmap(PHYTEST, POWERDOWN_SSP, 3), dump_regmap(PHYTEST, POWERDOWN_HSP, 2), dump_regmap(PHYRESUME, BYPASS_SEL, 4), dump_regmap(PHYRESUME, BYPASS_DM_EN, 3), dump_regmap(PHYRESUME, BYPASS_DP_EN, 2), dump_regmap(PHYRESUME, BYPASS_DM_DATA, 1), dump_regmap(PHYRESUME, BYPASS_DP_DATA, 0), dump_regmap_mask(PHYPCSVAL, PCS_RX_LOS_MASK_VAL, 0), dump_regmap_mask(LINKPORT, HOST_NUM_U3_PORT, 13), dump_regmap_mask(LINKPORT, HOST_NUM_U2_PORT, 9), dump_regmap(LINKPORT, HOST_U3_PORT_DISABLE, 8), dump_regmap(LINKPORT, HOST_U2_PORT_DISABLE, 7), dump_regmap(LINKPORT, PORT_POWER_CONTROL, 6), dump_regmap(LINKPORT, HOST_PORT_OVCR_U3, 5), dump_regmap(LINKPORT, HOST_PORT_OVCR_U2, 4), dump_regmap(LINKPORT, HOST_PORT_OVCR_U3_SEL, 3), dump_regmap(LINKPORT, HOST_PORT_OVCR_U2_SEL, 2), dump_regmap(LINKPORT, PERM_ATTACH_U2, 0), dump_regmap_mask(PHYPARAM2, TX_VBOOST_LVL, 3), dump_regmap_mask(PHYPARAM2, LOS_BIAS, 0), }; static int debugfs_phy_power_state(struct exynos_usbdrd_phy *phy_drd, int phy_index) { struct regmap *reg_pmu; u32 pmu_offset; int phy_on; int ret; reg_pmu = phy_drd->phys[phy_index].reg_pmu; pmu_offset = phy_drd->phys[phy_index].pmu_offset; ret = regmap_read(reg_pmu, pmu_offset, &phy_on); if (ret) { dev_err(phy_drd->dev, "Can't read 0x%x\n", pmu_offset); return ret; } phy_on &= phy_drd->phys[phy_index].pmu_mask; return phy_on; } static int debugfs_print_regmap(struct seq_file *s, const struct debugfs_regmap32 *regs, int nregs, void __iomem *base, const struct debugfs_reg32 *parent) { int i, j = 0; int bit = 0; unsigned int bitmask; int max_string = 24; int calc_tab; u32 bit_value, reg_value; reg_value = readl(base + parent->offset); seq_printf(s, "%s (0x%04lx) : 0x%08x\n", parent->name, parent->offset, reg_value); for (i = 0; i < nregs; i++, regs++) { if (!strcmp(regs->name, parent->name)) { bit_value = (reg_value & regs->bitmask) >> regs->bitoffset; seq_printf(s, "\t%s", regs->bitname); calc_tab = max_string/8 - strlen(regs->bitname)/8; for (j = 0 ; j < calc_tab; j++) seq_printf(s, "\t"); if (regs->mask) { bitmask = regs->bitmask; bitmask = bitmask >> regs->bitoffset; while (bitmask) { bitmask = bitmask >> 1; bit++; } seq_printf(s, "[%d:%d]\t: 0x%x\n", (int)regs->bitoffset, ((int)regs->bitoffset + bit - 1), bit_value); bit = 0; } else { seq_printf(s, "[%d]\t: 0x%x\n", (int)regs->bitoffset, bit_value); } } } return 0; } static int debugfs_show_regmap(struct seq_file *s, void *data) { struct exynos_debugfs_prvdata *prvdata = s->private; struct debugfs_regset_map *regmap = prvdata->regmap; struct debugfs_regset32 *regset = prvdata->regset; const struct debugfs_reg32 *regs = regset->regs; int phy_on, i = 0; phy_on = debugfs_phy_power_state(prvdata->phy_drd, 0); if (phy_on < 0) { seq_printf(s, "can't read PHY register, error : %d\n", phy_on); return -EIO; } if (!phy_on) { seq_printf(s, "can't get PHY register, PHY: Power OFF\n"); return 0; } for (i = 0; i < regset->nregs; i++, regs++) { debugfs_print_regmap(s, regmap->regs, regmap->nregs, regset->base, regs); } return 0; } static int debugfs_open_regmap(struct inode *inode, struct file *file) { return single_open(file, debugfs_show_regmap, inode->i_private); } static const struct file_operations fops_regmap = { .open = debugfs_open_regmap, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; int debugfs_print_regdump(struct seq_file *s, struct exynos_usbdrd_phy *phy_drd, const struct debugfs_reg32 *regs, int nregs, void __iomem *base) { int phy_on; int i; for (i = 0; i < EXYNOS_DRDPHYS_NUM; i++) { phy_on = debugfs_phy_power_state(phy_drd, i); if (phy_on < 0) { seq_printf(s, "can't read PHY register, error : %d\n", phy_on); return phy_on; } if (!phy_on) { seq_printf(s, "can't get PHY register, PHY%d : Power OFF\n", i); continue; } for (i = 0; i < nregs; i++, regs++) { seq_printf(s, "%s", regs->name); if (strlen(regs->name) < 8) seq_printf(s, "\t\t"); else seq_printf(s, "\t"); seq_printf(s, "= 0x%08x\n", readl(base + regs->offset)); } } return 0; } static int debugfs_show_regdump(struct seq_file *s, void *data) { struct exynos_debugfs_prvdata *prvdata = s->private; struct debugfs_regset32 *regset = prvdata->regset; int ret; ret = debugfs_print_regdump(s, prvdata->phy_drd, regset->regs, regset->nregs, regset->base); if (ret < 0) return ret; return 0; } static int debugfs_open_regdump(struct inode *inode, struct file *file) { return single_open(file, debugfs_show_regdump, inode->i_private); } static const struct file_operations fops_regdump = { .open = debugfs_open_regdump, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int debugfs_show_bitset(struct seq_file *s, void *data) { char *b_name = s->private; struct debugfs_regset_map *regmap = prvdata->regmap; const struct debugfs_regmap32 *cmp = regmap->regs; const struct debugfs_regmap32 *regs; unsigned int bitmask; int i, bit = 0; u32 reg_value, bit_value; u32 detect_regs = 0; for (i = 0; i < regmap->nregs; i++, cmp++) { if (!strcmp(cmp->bitname, b_name)) { regs = cmp; detect_regs = 1; break; } } if (!detect_regs) return -EINVAL; reg_value = readl(prvdata->regset->base + regs->offset); bit_value = (reg_value & regs->bitmask) >> regs->bitoffset; if (regs->mask) { bitmask = regs->bitmask; bitmask = bitmask >> regs->bitoffset; while (bitmask) { bitmask = bitmask >> 1; bit++; } seq_printf(s, "%s [%d:%d] = 0x%x\n", regs->name, (int)regs->bitoffset, ((int)regs->bitoffset + bit - 1), bit_value); } else { seq_printf(s, "%s [%d] = 0x%x\n", regs->name, (int)regs->bitoffset, bit_value); } return 0; } static ssize_t debugfs_write_regset(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct seq_file *s = file->private_data; char *reg_name = s->private; struct debugfs_regset32 *regset = prvdata->regset; const struct debugfs_reg32 *regs = regset->regs; unsigned long value; char buf[8]; int i; if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; value = simple_strtol(buf, NULL, 16); for (i = 0; i < regset->nregs; i++, regs++) { if (!strcmp(regs->name, reg_name)) break; } writel(value, regset->base + regs->offset); return count; } static ssize_t debugfs_write_bitset(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct seq_file *s = file->private_data; char *b_name = s->private; struct debugfs_regset_map *regmap = prvdata->regmap; const struct debugfs_regmap32 *regs = regmap->regs; unsigned long value; char buf[32]; int i; u32 reg_value; if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) { seq_printf(s, "%s, write error\n", __func__); return -EFAULT; } value = simple_strtol(buf, NULL, 2); for (i = 0; i < regmap->nregs; i++, regs++) { if (!strcmp(regs->bitname, b_name)) break; } value = value << regs->bitoffset; reg_value = readl(prvdata->regset->base + regs->offset); reg_value &= ~(regs->bitmask); reg_value |= (u32)value; writel(reg_value, prvdata->regset->base + regs->offset); return count; } static int debugfs_open_bitset(struct inode *inode, struct file *file) { return single_open(file, debugfs_show_bitset, inode->i_private); } static int debugfs_show_regset(struct seq_file *s, void *data) { char *p_name = s->private; struct debugfs_regset32 *regset = prvdata->regset; struct debugfs_regset_map *regmap = prvdata->regmap; const struct debugfs_reg32 *regs = regset->regs; const struct debugfs_reg32 *parents; u32 detect_regs = 0; int i; for (i = 0; i < regset->nregs; i++, regs++) { if (!strcmp(regs->name, p_name)) { parents = regs; detect_regs = 1; break; } } if (!detect_regs) return -EINVAL; debugfs_print_regmap(s, prvdata->regmap->regs, regmap->nregs, regset->base, parents); return 0; } static int debugfs_open_regset(struct inode *inode, struct file *file) { return single_open(file, debugfs_show_regset, inode->i_private); } static const struct file_operations fops_regset = { .open = debugfs_open_regset, .write = debugfs_write_regset, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static const struct file_operations fops_bitset = { .open = debugfs_open_bitset, .write = debugfs_write_bitset, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int debugfs_create_regfile(struct exynos_debugfs_prvdata *prvdata, const struct debugfs_reg32 *parents, struct dentry *root) { struct debugfs_regset_map *regmap = prvdata->regmap; const struct debugfs_regmap32 *regs = regmap->regs; struct dentry *file; int i, ret; file = debugfs_create_file(parents->name, S_IRUGO | S_IWUGO, root, parents->name, &fops_regset); if (!file) { ret = -ENOMEM; return ret; } for (i = 0; i < regmap->nregs; i++, regs++) { if (!strcmp(regs->name, parents->name)) { file = debugfs_create_file(regs->bitname, S_IRUGO | S_IWUGO, root, regs->bitname, &fops_bitset); if (!file) { ret = -ENOMEM; return ret; } } } return 0; } static int debugfs_create_regdir(struct exynos_debugfs_prvdata *prvdata, struct dentry *root) { struct exynos_usbdrd_phy *phy_drd = prvdata->phy_drd; struct debugfs_regset32 *regset = prvdata->regset; const struct debugfs_reg32 *regs = regset->regs; struct dentry *dir; int ret, i; for (i = 0; i < regset->nregs; i++, regs++) { dir = debugfs_create_dir(regs->name, root); if (!dir) { dev_err(phy_drd->dev, "failed to create '%s' reg dir", regs->name); return -ENOMEM; } ret = debugfs_create_regfile(prvdata, regs, dir); if (ret < 0) { dev_err(phy_drd->dev, "failed to create bitfile for %s, error : %d\n", regs->name, ret); return ret; } } return 0; } int exynos_usbdrd_debugfs_init(struct exynos_usbdrd_phy *phy_drd) { struct device *dev = phy_drd->dev; struct dentry *root; struct dentry *dir; struct dentry *file; u32 version = phy_drd->usbphy_info.version; int ret; root = debugfs_create_dir(dev_name(dev), NULL); if (!root) { dev_err(dev, "failed to create root directory for USBPHY debugfs"); ret = -ENOMEM; goto err0; } prvdata = devm_kmalloc(dev, sizeof(struct exynos_debugfs_prvdata), GFP_KERNEL); if (!prvdata) { dev_err(dev, "failed to alloc private data for debugfs"); ret = -ENOMEM; goto err1; } prvdata->root = root; prvdata->phy_drd = phy_drd; prvdata->regset = devm_kmalloc(dev, sizeof(*prvdata->regset), GFP_KERNEL); if (!prvdata->regset) { dev_err(dev, "failed to alloc regmap"); ret = -ENOMEM; goto err1; } if ((version >= EXYNOS_USBCON_VER_02_0_0) && (version <= EXYNOS_USBCON_VER_02_MAX)) { /* for USB2PHY */ prvdata->regset->regs = exynos_usb2drd_regs; prvdata->regset->nregs = ARRAY_SIZE(exynos_usb2drd_regs); } else if ((version >= EXYNOS_USBCON_VER_03_0_0) && (version <= EXYNOS_USBCON_VER_03_MAX)) { /* for USB3PHY Lhotse */ prvdata->regset->regs = exynos_usb3drd_phycon_regs; prvdata->regset->nregs = ARRAY_SIZE(exynos_usb3drd_phycon_regs); } else { /* for USB3PHY */ prvdata->regset->regs = exynos_usb3drd_regs; prvdata->regset->nregs = ARRAY_SIZE(exynos_usb3drd_regs); } prvdata->regset->base = phy_drd->reg_phy; prvdata->regmap = devm_kmalloc(dev, sizeof(*prvdata->regmap), GFP_KERNEL); if (!prvdata->regmap) { dev_err(dev, "failed to alloc regmap"); ret = -ENOMEM; goto err1; } if ((version >= EXYNOS_USBCON_VER_02_0_0) && /* for USB2PHY */ (version <= EXYNOS_USBCON_VER_02_MAX)) { prvdata->regmap->regs = exynos_usb2drd_regmap; prvdata->regmap->nregs = ARRAY_SIZE(exynos_usb2drd_regmap); } else if ((version >= EXYNOS_USBCON_VER_03_0_0) && (version <= EXYNOS_USBCON_VER_03_MAX)) { /* for USB3PHY Lhotse */ prvdata->regmap->regs = exynos_usb3drd_phycon_regmap; prvdata->regmap->nregs = ARRAY_SIZE(exynos_usb3drd_phycon_regmap); } else { /* for USB3PHY */ prvdata->regmap->regs = exynos_usb3drd_regmap; prvdata->regmap->nregs = ARRAY_SIZE(exynos_usb3drd_regmap); } file = debugfs_create_file("regdump", S_IRUGO, root, prvdata, &fops_regdump); if (!file) { dev_err(dev, "failed to create file for register dump"); ret = -ENOMEM; goto err1; } file = debugfs_create_file("regmap", S_IRUGO, root, prvdata, &fops_regmap); if (!file) { dev_err(dev, "failed to create file for register dump"); ret = -ENOMEM; goto err1; } dir = debugfs_create_dir("regset", root); if (!dir) { ret = -ENOMEM; goto err1; } ret = debugfs_create_regdir(prvdata, dir); if (ret < 0) { dev_err(dev, "failed to create regfile, error = %d\n", ret); goto err1; } return 0; err1: debugfs_remove_recursive(root); err0: return ret; }