blob: 985aecd1fbd718e023c8e79870a922e264aa1e9b [file] [log] [blame]
/*
* 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 <k-hye.yun@samsung.com>
*
* 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 <linux/io.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/ptrace.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/usb/ch9.h>
#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;
}