Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b02e768 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "scsi: ufs-msm: avoid full UFS initialization on system resume"

parents 66f6f694 a6582b5d
Loading
Loading
Loading
Loading
+276 −25
Original line number Diff line number Diff line
@@ -1309,6 +1309,107 @@ static struct msm_ufs_phy_calibration phy_cal_table_rate_B[] = {
	},
};

static struct msm_ufs_phy_calibration cached_phy_regs[] = {
	{QSERDES_COM_PLL_CRCTRL},
	{QSERDES_COM_PLL_CNTRL},
	{QSERDES_COM_SYSCLK_EN_SEL},
	{QSERDES_COM_SYS_CLK_CTRL},
	{QSERDES_COM_PLL_CLKEPDIV},
	{QSERDES_COM_DEC_START1},
	{QSERDES_COM_DEC_START2},
	{QSERDES_COM_DIV_FRAC_START1},
	{QSERDES_COM_DIV_FRAC_START2},
	{QSERDES_COM_DIV_FRAC_START3},
	{QSERDES_COM_PLLLOCK_CMP1},
	{QSERDES_COM_PLLLOCK_CMP2},
	{QSERDES_COM_PLLLOCK_CMP3},
	{QSERDES_COM_PLLLOCK_CMP_EN},
	{QSERDES_COM_RESETSM_CNTRL},
	{QSERDES_COM_PLL_RXTXEPCLK_EN},
	{QSERDES_RX_PWM_CNTRL1(0)},
	{QSERDES_RX_PWM_CNTRL1(1)},
	{QSERDES_RX_CDR_CONTROL(0)},
	{QSERDES_RX_CDR_CONTROL_HALF(0)},
	{QSERDES_RX_CDR_CONTROL_QUARTER(0)},
	{QSERDES_RX_CDR_CONTROL(1)},
	{QSERDES_RX_CDR_CONTROL_HALF(1)},
	{QSERDES_RX_CDR_CONTROL_QUARTER(1)},
	{QSERDES_RX_SIGDET_CNTRL(0)},
	{QSERDES_RX_SIGDET_CNTRL(1)},
	{QSERDES_RX_SIGDET_CNTRL2(0)},
	{QSERDES_RX_SIGDET_CNTRL2(1)},
	{QSERDES_RX_RX_EQ_GAIN1(0)},
	{QSERDES_RX_RX_EQ_GAIN2(0)},
	{QSERDES_RX_RX_EQ_GAIN1(1)},
	{QSERDES_RX_RX_EQ_GAIN2(1)},
	{QSERDES_COM_PLL_IP_SETI},
	{QSERDES_COM_PLL_CP_SETI},
	{QSERDES_COM_PLL_IP_SETP},
	{QSERDES_COM_PLL_CP_SETP},
	{UFS_PHY_PWM_G1_CLK_DIVIDER},
	{UFS_PHY_PWM_G2_CLK_DIVIDER},
	{UFS_PHY_PWM_G3_CLK_DIVIDER},
	{UFS_PHY_PWM_G4_CLK_DIVIDER},
	{UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER},
	{UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER},
	{UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER},
	{UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER},
	{UFS_PHY_OMC_STATUS_RDVAL},
	{UFS_PHY_LINE_RESET_TIME},
	{UFS_PHY_LINE_RESET_GRANULARITY},
	{UFS_PHY_TSYNC_RSYNC_CNTL},
	{UFS_PHY_PLL_CNTL},
	{UFS_PHY_TX_LARGE_AMP_DRV_LVL},
	{UFS_PHY_TX_SMALL_AMP_DRV_LVL},
	{UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL},
	{UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL},
	{UFS_PHY_CFG_CHANGE_CNT_VAL},
	{UFS_PHY_RX_SYNC_WAIT_TIME},
	{UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY},
	{UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY},
	{UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY},
	{UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY},
	{UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY},
	{UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY},
	{UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY},
	{UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY},
	{QSERDES_RX_CDR_CONTROL3(0)},
	{QSERDES_RX_CDR_CONTROL3(1)},
	{QSERDES_COM_RES_TRIM_OFFSET},
	{QSERDES_COM_BGTC},
	{QSERDES_COM_PLL_AMP_OS},
};

static struct msm_ufs_stored_attributes cached_phy_attr[] = {
	{TX_MODE},
	{TX_HSRATE_SERIES},
	{TX_HSGEAR},
	{TX_PWMGEAR},
	{TX_AMPLITUDE},
	{TX_HS_SLEWRATE},
	{TX_SYNC_SOURCE},
	{TX_HS_PREPARE_LENGTH},
	{TX_LS_PREPARE_LENGTH},
	{TX_LCC_ENABLE},
	{TX_PWM_BURST_CLOSURE_EXTENSION},
	{TX_BYPASS_8B10B_ENABLE},
	{TX_DRIVER_POLARITY},
	{TX_HS_UNTERMINATED_LINE_DRIVE_ENABLE},
	{TX_LS_TERMINATED_LINE_DRIVE_ENABLE},
	{TX_LCC_SEQUENCER},
	{TX_MIN_ACTIVATETIME},
	{TX_PWM_G6_G7_SYNC_LENGTH},
	{RX_MODE},
	{RX_HSRATE_SERIES},
	{RX_HSGEAR},
	{RX_PWMGEAR},
	{RX_LS_TERMINATED_ENABLE},
	{RX_HS_UNTERMINATED_ENABLE},
	{RX_ENTER_HIBERN8},
	{RX_BYPASS_8B10B_ENABLE},
	{RX_TERMINATION_FORCE_ENABLE},
};

static struct msm_ufs_phy *msm_get_ufs_phy(struct device *dev)
{
	int err  = -EPROBE_DEFER;
@@ -1793,6 +1894,90 @@ static int msm_ufs_phy_power_off(struct msm_ufs_phy *phy)
	return 0;
}

static u32 msm_ufs_read_phy_attr(struct ufs_hba *hba, u32 attr)
{
	struct msm_ufs_host *host = hba->priv;
	struct msm_ufs_phy *phy = host->phy;
	u32 l0, l1;

	writel_relaxed(attr, phy->mmio + UFS_PHY_RMMI_ATTRID);
	/* Read attribute value for both Lanes */
	writel_relaxed((UFS_PHY_RMMI_CFGRD_L0 | UFS_PHY_RMMI_CFGRD_L1),
		       phy->mmio + UFS_PHY_RMMI_ATTR_CTRL);

	l0 = readl_relaxed(phy->mmio + UFS_PHY_RMMI_ATTRRDVAL_L0_STATUS);
	l1 = readl_relaxed(phy->mmio + UFS_PHY_RMMI_ATTRRDVAL_L1_STATUS);
	/* Both lanes should have the same value for same attribute type */
	if (unlikely(l0 != l1))
		dev_warn(phy->dev, "%s: attr 0x%x values are not same for Lane-0 and Lane-1, l0=0x%x, l1=0x%x",
				__func__, attr, l0, l1);

	/* must clear now */
	writel_relaxed(0x00, phy->mmio + UFS_PHY_RMMI_ATTR_CTRL);

	return l0;
}

static void msm_ufs_write_phy_attr(struct ufs_hba *hba, u32 attr, u32 val)
{
	struct msm_ufs_host *host = hba->priv;
	struct msm_ufs_phy *phy = host->phy;

	writel_relaxed(attr, phy->mmio + UFS_PHY_RMMI_ATTRID);
	writel_relaxed(val, phy->mmio + UFS_PHY_RMMI_ATTRWRVAL);
	/* update attribute for both Lanes */
	writel_relaxed((UFS_PHY_RMMI_CFGWR_L0 | UFS_PHY_RMMI_CFGWR_L1),
		       phy->mmio + UFS_PHY_RMMI_ATTR_CTRL);
	if (is_mphy_tx_attr(attr))
		writel_relaxed((UFS_PHY_RMMI_TX_CFGUPDT_L0 |
				UFS_PHY_RMMI_TX_CFGUPDT_L1),
			       phy->mmio + UFS_PHY_RMMI_ATTR_CTRL);
	else
		writel_relaxed((UFS_PHY_RMMI_RX_CFGUPDT_L0 |
				UFS_PHY_RMMI_RX_CFGUPDT_L1),
			       phy->mmio + UFS_PHY_RMMI_ATTR_CTRL);

	/* must clear now */
	writel_relaxed(0x00, phy->mmio + UFS_PHY_RMMI_ATTR_CTRL);
}

static void msm_ufs_save_phy_configuration(struct ufs_hba *hba)
{
	struct msm_ufs_host *host = hba->priv;
	struct msm_ufs_phy *phy = host->phy;
	int i;

	for (i = 0; i < ARRAY_SIZE(cached_phy_regs); i++)
		cached_phy_regs[i].cfg_value = readl_relaxed(phy->mmio +
					       cached_phy_regs[i].reg_offset);

	for (i = 0; i < ARRAY_SIZE(cached_phy_attr); i++)
		cached_phy_attr[i].value = msm_ufs_read_phy_attr(hba,
						cached_phy_attr[i].att);

}

static void msm_ufs_restore_phy_swi_regs(struct msm_ufs_phy *phy)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(cached_phy_regs); i++)
		writel_relaxed(cached_phy_regs[i].cfg_value, phy->mmio +
				cached_phy_regs[i].reg_offset);

	/* flush buffered writes */
	mb();
}

static void msm_ufs_restore_phy_attrs(struct ufs_hba *hba)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(cached_phy_attr); i++)
		msm_ufs_write_phy_attr(hba, cached_phy_attr[i].att,
				       cached_phy_attr[i].value);
}

static inline void msm_ufs_assert_reset(struct ufs_hba *hba)
{
	ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET,
@@ -1807,22 +1992,30 @@ static inline void msm_ufs_deassert_reset(struct ufs_hba *hba)
	mb();
}

static int msm_ufs_hce_enable_notify(struct ufs_hba *hba, bool status)
static int msm_ufs_power_up_sequence(struct ufs_hba *hba,
				     enum msm_ufs_phy_init_type type)
{
	struct msm_ufs_host *host = hba->priv;
	struct msm_ufs_phy *phy = host->phy;
	u32 val;
	int err = -EINVAL;
	int err = 0;

	switch (status) {
	case PRE_CHANGE:
	switch (type) {
	case UFS_PHY_INIT_FULL:
		/* Assert PHY reset and apply PHY calibration values */
		msm_ufs_assert_reset(hba);

		/* provide 1ms delay to let the reset pulse propagate */
		usleep_range(1000, 1100);

		msm_ufs_phy_calibrate(hba);
		break;
	case UFS_PHY_INIT_CFG_RESTORE:
		msm_ufs_restore_phy_swi_regs(phy);
		break;
	default:
		dev_err(phy->dev, "%s: Unknown calibration type, %d\n",
				__func__, type);
		return -EINVAL;
	}

	/* De-assert PHY reset and start serdes */
	msm_ufs_deassert_reset(hba);
@@ -1835,14 +2028,26 @@ static int msm_ufs_hce_enable_notify(struct ufs_hba *hba, bool status)

	msm_ufs_phy_start_serdes(phy);

	if (type == UFS_PHY_INIT_CFG_RESTORE)
		msm_ufs_restore_phy_attrs(hba);

	/* poll for PCS_READY for max. 1sec */
	err = readl_poll_timeout(phy->mmio + UFS_PHY_PCS_READY_STATUS,
			val, (val & MASK_PCS_READY), 10, 1000000);
		if (err) {
			dev_err(phy->dev, "%s: phy init failed, %d\n",
					__func__, err);
			break;
	if (err)
		dev_err(phy->dev, "%s: phy init failed, %d\n", __func__, err);

	return err;
}

static int msm_ufs_hce_enable_notify(struct ufs_hba *hba, bool status)
{
	struct msm_ufs_host *host = hba->priv;
	int err = 0;

	switch (status) {
	case PRE_CHANGE:
		msm_ufs_power_up_sequence(hba, UFS_PHY_INIT_FULL);
		/*
		 * The PHY PLL output is the source of tx/rx lane symbol clocks.
		 * Hence, enable the lane clocks only after PHY is initialized.
@@ -1853,6 +2058,8 @@ static int msm_ufs_hce_enable_notify(struct ufs_hba *hba, bool status)
		/* check if UFS PHY moved from DISABLED to HIBERN8 */
		err = msm_ufs_check_hibern8(hba);
	default:
		dev_err(hba->dev, "%s: invalid status %d\n", __func__, status);
		err = -EINVAL;
		break;
	}

@@ -2019,6 +2226,10 @@ static int msm_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
	 * rail and low noise analog power rail for PLL can be switched off.
	 */
	if (!ufshcd_is_link_active(hba)) {
		if ((phy->quirks & MSM_UFS_PHY_QUIRK_CFG_RESTORE)
		    && ufshcd_is_link_hibern8(hba))
			msm_ufs_save_phy_configuration(hba);

		msm_ufs_disable_phy_ref_clk(phy);
		writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
		/*
@@ -2034,15 +2245,50 @@ out:
	return ret;
}

static bool msm_ufs_is_phy_config_restore_required(struct ufs_hba *hba)
{
	struct msm_ufs_host *host = hba->priv;
	struct msm_ufs_phy *phy = host->phy;

	return (phy->quirks & MSM_UFS_PHY_QUIRK_CFG_RESTORE)
		&& ufshcd_is_link_hibern8(hba)
		&& hba->is_sys_suspended;
}

static int msm_ufs_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
	struct msm_ufs_host *host = hba->priv;
	struct msm_ufs_phy *phy = host->phy;
	int err;

	if (!phy)
		return 0;

	return msm_ufs_phy_power_on(phy);
	if (msm_ufs_is_phy_config_restore_required(hba)) {
		msm_ufs_assert_reset(hba);
		/* provide 1ms delay to let the reset pulse propagate */
		usleep_range(1000, 1100);
	}

	err = msm_ufs_phy_power_on(phy);
	if (err) {
		dev_err(hba->dev, "%s: failed enabling regs, err = %d\n",
						__func__, err);
		goto out;
	}

	if (msm_ufs_is_phy_config_restore_required(hba)) {
		err = msm_ufs_power_up_sequence(hba, UFS_PHY_INIT_CFG_RESTORE);
		if (err) {
			dev_err(hba->dev, "%s: phy power up sequence failed err = %d\n",
						__func__, err);
			goto out;
		}
		hba->is_sys_suspended = false;
	}

out:
	return err;
}

struct ufs_msm_dev_params {
@@ -2302,6 +2548,8 @@ out:
 */
static void msm_ufs_advertise_quirks(struct ufs_hba *hba)
{
	struct msm_ufs_host *host = hba->priv;
	struct msm_ufs_phy *phy = host->phy;
	u8 major;
	u16 minor, step;

@@ -2311,7 +2559,7 @@ static void msm_ufs_advertise_quirks(struct ufs_hba *hba)
	 * Interrupt aggregation and HIBERN8 on UFS HW controller revision 1.1.0
	 * is broken.
	 */
	if ((major == 0x1) && (minor == 0x001) && (step == 0x0000))
	if ((major == 0x1) && (minor == 0x001) && (step == 0x0000)) {
		hba->quirks |= (UFSHCD_QUIRK_BROKEN_INTR_AGGR
			      | UFSHCD_QUIRK_BROKEN_HIBERN8
			      | UFSHCD_QUIRK_BROKEN_VER_REG_1_1
@@ -2320,13 +2568,16 @@ static void msm_ufs_advertise_quirks(struct ufs_hba *hba)
			      | UFSHCD_QUIRK_BROKEN_2_TX_LANES
			      | UFSHCD_QUIRK_BROKEN_SUSPEND
			      | UFSHCD_BROKEN_LCC);
	else if ((major == 0x1) && (minor == 0x001) && (step == 0x0001))
	} else if ((major == 0x1) && (minor == 0x001) && (step == 0x0001)) {
		hba->quirks |= (UFSHCD_QUIRK_BROKEN_HIBERN8
			      | UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS
			      | UFSHCD_QUIRK_BROKEN_INTR_AGGR
			      | UFSHCD_QUIRK_BROKEN_SUSPEND
			      | UFSHCD_BROKEN_GEAR_CHANGE_INTO_HS
			      | UFSHCD_BROKEN_LCC);

		phy->quirks = MSM_UFS_PHY_QUIRK_CFG_RESTORE;
	}
}

static int msm_ufs_get_bus_vote(struct msm_ufs_host *host,
+57 −1
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -54,6 +54,16 @@ struct msm_ufs_phy_calibration {
	u32 cfg_value;
};

struct msm_ufs_stored_attributes {
	u32 att;
	u32 value;
};

enum msm_ufs_phy_init_type {
	UFS_PHY_INIT_FULL,
	UFS_PHY_INIT_CFG_RESTORE,
};

struct msm_ufs_phy_vreg {
	const char *name;
	struct regulator *reg;
@@ -76,6 +86,39 @@ struct msm_ufs_phy {
	bool is_ref_clk_enabled;
	struct msm_ufs_phy_vreg vdda_pll;
	struct msm_ufs_phy_vreg vdda_phy;
	unsigned int quirks;
	/*
	 * As part of UFS power management, UFS link would be put in hibernate
	 * and UFS device would be put in SLEEP mode as part of runtime/system
	 * suspend callback. But when system goes into suspend with VDD
	 * minimization, UFS PHY states are being reset which means UFS link
	 * hibernate exit command on system resume would fail.
	 * If this quirk is enabled then above issue is workaround by saving
	 * the UFS PHY state information before system goes into suspend and
	 * restoring the saved state information during system resume but
	 * before executing the hibern8 exit command.
	 * Note that this quirk will help restoring the PHY state if even when
	 * link in not kept in hibern8 during suspend.
	 *
	 * Here is the list of steps to save/restore the configuration:
	 * Before entering into system suspend:
	 *	1. Read Critical PCS SWI Registers  + less critical PHY CSR
	 *	2. Read RMMI Attributes
	 * Enter into system suspend
	 * After exiting from system suspend:
	 *	1. Set UFS_PHY_SOFT_RESET bit in UFS_CFG1 register of the UFS
	 *	   Controller
	 *	2. Write 0x01 to the UFS_PHY_POWER_DOWN_CONTROL register in the
	 *	   UFS PHY
	 *	3. Write back the values of the PHY SWI registers
	 *	4. Clear UFS_PHY_SOFT_RESET bit in UFS_CFG1 register of the UFS
	 *	   Controller
	 *	5. Write 0x01 to the UFS_PHY_PHY_START in the UFS PHY. This will
	 *	   start the PLL calibration and bring-up of the PHY.
	 *	6. Write back the values to the PHY RMMI Attributes
	 *	7. Wait for UFS_PHY_PCS_READY_STATUS[0] to be '1'
	 */
	#define MSM_UFS_PHY_QUIRK_CFG_RESTORE		(1 << 0)
};

struct msm_ufs_bus_vote {
@@ -248,6 +291,19 @@ static int msm_ufs_update_bus_bw_vote(struct msm_ufs_host *host);
#define UFS_PHY_DEBUG_BUS_1_STATUS                          PHY_OFF(0x154)
#define UFS_PHY_DEBUG_BUS_2_STATUS                          PHY_OFF(0x158)
#define UFS_PHY_DEBUG_BUS_3_STATUS                          PHY_OFF(0x15C)
#define UFS_PHY_RMMI_ATTR_CTRL				    PHY_OFF(0x16C)
#define UFS_PHY_RMMI_RX_CFGUPDT_L1	(1 << 7)
#define UFS_PHY_RMMI_TX_CFGUPDT_L1	(1 << 6)
#define UFS_PHY_RMMI_CFGWR_L1		(1 << 5)
#define UFS_PHY_RMMI_CFGRD_L1		(1 << 4)
#define UFS_PHY_RMMI_RX_CFGUPDT_L0	(1 << 3)
#define UFS_PHY_RMMI_TX_CFGUPDT_L0	(1 << 2)
#define UFS_PHY_RMMI_CFGWR_L0		(1 << 1)
#define UFS_PHY_RMMI_CFGRD_L0		(1 << 0)
#define UFS_PHY_RMMI_ATTRID				    PHY_OFF(0x170)
#define UFS_PHY_RMMI_ATTRWRVAL				    PHY_OFF(0x174)
#define UFS_PHY_RMMI_ATTRRDVAL_L0_STATUS		    PHY_OFF(0x178)
#define UFS_PHY_RMMI_ATTRRDVAL_L1_STATUS		    PHY_OFF(0x17C)

/* TX LANE n (0, 1) registers */
#define QSERDES_TX_BIST_MODE_LANENO(n)                      TX_OFF(n, 0x00)
+2 −0
Original line number Diff line number Diff line
@@ -5608,6 +5608,8 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
out:
	trace_ufshcd_system_suspend(dev_name(hba->dev), ret,
			ktime_to_us(ktime_sub(ktime_get(), start)));
	if (!ret)
		hba->is_sys_suspended = true;
	return ret;
}
EXPORT_SYMBOL(ufshcd_system_suspend);
+1 −0
Original line number Diff line number Diff line
@@ -550,6 +550,7 @@ struct ufs_hba {
	struct ufs_stats ufs_stats;
	struct debugfs_files debugfs_files;
#endif
	bool is_sys_suspended;
};

/* Returns true if clocks can be gated. Otherwise false */
+34 −1
Original line number Diff line number Diff line
@@ -15,8 +15,41 @@
/*
 * M-TX Configuration Attributes
 */
#define TX_LCC_ENABLE		0x2C
#define TX_MODE					0x0021
#define TX_HSRATE_SERIES			0x0022
#define TX_HSGEAR				0x0023
#define TX_PWMGEAR				0x0024
#define TX_AMPLITUDE				0x0025
#define TX_HS_SLEWRATE				0x0026
#define TX_SYNC_SOURCE				0x0027
#define TX_HS_SYNC_LENGTH			0x0028
#define TX_HS_PREPARE_LENGTH			0x0029
#define TX_LS_PREPARE_LENGTH			0x002A
#define TX_HIBERN8_CONTROL			0x002B
#define TX_LCC_ENABLE				0x002C
#define TX_PWM_BURST_CLOSURE_EXTENSION		0x002D
#define TX_BYPASS_8B10B_ENABLE			0x002E
#define TX_DRIVER_POLARITY			0x002F
#define TX_HS_UNTERMINATED_LINE_DRIVE_ENABLE	0x0030
#define TX_LS_TERMINATED_LINE_DRIVE_ENABLE	0x0031
#define TX_LCC_SEQUENCER			0x0032
#define TX_MIN_ACTIVATETIME			0x0033
#define TX_PWM_G6_G7_SYNC_LENGTH		0x0034

/*
 * M-RX Configuration Attributes
 */
#define RX_MODE					0x00A1
#define RX_HSRATE_SERIES			0x00A2
#define RX_HSGEAR				0x00A3
#define RX_PWMGEAR				0x00A4
#define RX_LS_TERMINATED_ENABLE			0x00A5
#define RX_HS_UNTERMINATED_ENABLE		0x00A6
#define RX_ENTER_HIBERN8			0x00A7
#define RX_BYPASS_8B10B_ENABLE			0x00A8
#define RX_TERMINATION_FORCE_ENABLE		0x0089

#define is_mphy_tx_attr(attr)			(attr < RX_MODE)
/*
 * PHY Adpater attributes
 */