1
0
Fork 0

MLK-24050-1 phy: freescale: imx8mq-usb: add phy tuning

Add USB PHY parameters tuning for USB certifications.

Reviewed-by: Peter Chen <peter.chen@nxp.com>
Signed-off-by: Li Jun <jun.li@nxp.com>
(cherry picked from commit 4fee6f2d570373d53d83e2c1c76cf8b40326d20a)
zero-colors
Li Jun 2020-05-16 09:58:44 +08:00
parent 56bffa9cd6
commit 0b1bb629ee
1 changed files with 106 additions and 0 deletions

View File

@ -32,11 +32,26 @@
#define PHY_CTRL2_TXENABLEN0 BIT(8)
#define PHY_CTRL2_OTG_DISABLE BIT(9)
#define PHY_CTRL3 0xc
#define PHY_CTRL3_COMPDISTUNE_MASK GENMASK(2, 0)
#define PHY_CTRL3_TXPREEMP_TUNE_MASK GENMASK(16, 15)
#define PHY_CTRL3_TXPREEMP_TUNE_SHIFT 15
#define PHY_CTRL3_TXRISE_TUNE_MASK GENMASK(21, 20)
#define PHY_CTRL3_TXRISE_TUNE_SHIFT 20
/* 1111: +24% ... 0000: -6% step: 2% */
#define PHY_CTRL3_TXVREF_TUNE_MASK GENMASK(25, 22)
#define PHY_CTRL3_TXVREF_TUNE_SHIFT 22
#define PHY_CTRL4 0x10
#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(20, 15)
#define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_SHIFT 15
#define PHY_CTRL5 0x14
#define PHY_CTRL5_DMPWD_OVERRIDE_SEL BIT(23)
#define PHY_CTRL5_DMPWD_OVERRIDE BIT(22)
#define PHY_CTRL5_DPPWD_OVERRIDE_SEL BIT(21)
#define PHY_CTRL5_DPPWD_OVERRIDE BIT(20)
#define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0)
#define PHY_CTRL6 0x18
#define PHY_CTRL6_RXTERM_OVERRIDE_SEL BIT(29)
@ -49,6 +64,8 @@
#define PHY_STS0_FSVPLUS BIT(3)
#define PHY_STS0_FSVMINUS BIT(2)
#define PHY_TUNE_DEFAULT 0xffffffff
struct imx8mq_usb_phy {
struct phy *phy;
struct clk *clk;
@ -57,6 +74,12 @@ struct imx8mq_usb_phy {
struct notifier_block chg_det_nb;
struct power_supply *vbus_power_supply;
enum power_supply_usb_type chg_type;
u32 pcs_tx_swing_full;
u32 pcs_tx_deemph_3p5db;
u32 tx_vref_tune;
u32 tx_rise_tune;
u32 tx_preemp_amp_tune;
u32 comp_dis_tune;
};
static int imx8mq_usb_phy_init(struct phy *phy)
@ -123,6 +146,58 @@ static int imx8mp_usb_phy_init(struct phy *phy)
value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
writel(value, imx_phy->base + PHY_CTRL1);
/* PHY tuning */
if (imx_phy->pcs_tx_deemph_3p5db != PHY_TUNE_DEFAULT) {
value = readl(imx_phy->base + PHY_CTRL4);
value &= ~PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK;
value |= imx_phy->pcs_tx_deemph_3p5db <<
PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_SHIFT;
writel(value, imx_phy->base + PHY_CTRL4);
}
if (imx_phy->pcs_tx_swing_full != PHY_TUNE_DEFAULT) {
value = readl(imx_phy->base + PHY_CTRL5);
value &= ~PHY_CTRL5_PCS_TX_SWING_FULL_MASK;
value |= imx_phy->pcs_tx_swing_full;
writel(value, imx_phy->base + PHY_CTRL5);
}
if ((imx_phy->tx_vref_tune & imx_phy->tx_rise_tune &
imx_phy->tx_preemp_amp_tune & imx_phy->comp_dis_tune) ==
PHY_TUNE_DEFAULT)
/* If all are the default values, no need update. */
return 0;
value = readl(imx_phy->base + PHY_CTRL3);
if (imx_phy->tx_vref_tune == PHY_TUNE_DEFAULT)
imx_phy->tx_vref_tune = (value & PHY_CTRL3_TXVREF_TUNE_MASK) >>
PHY_CTRL3_TXVREF_TUNE_SHIFT;
if (imx_phy->tx_rise_tune == PHY_TUNE_DEFAULT)
imx_phy->tx_rise_tune = (value & PHY_CTRL3_TXRISE_TUNE_MASK) >>
PHY_CTRL3_TXRISE_TUNE_SHIFT;
if (imx_phy->tx_preemp_amp_tune == PHY_TUNE_DEFAULT)
imx_phy->tx_preemp_amp_tune = (value &
PHY_CTRL3_TXPREEMP_TUNE_MASK) >>
PHY_CTRL3_TXPREEMP_TUNE_SHIFT;
if (imx_phy->comp_dis_tune == PHY_TUNE_DEFAULT)
imx_phy->comp_dis_tune = value & PHY_CTRL3_COMPDISTUNE_MASK;
value &= ~(PHY_CTRL3_TXVREF_TUNE_MASK |
PHY_CTRL3_TXRISE_TUNE_MASK |
PHY_CTRL3_TXPREEMP_TUNE_MASK |
PHY_CTRL3_COMPDISTUNE_MASK);
value |= imx_phy->tx_vref_tune << PHY_CTRL3_TXVREF_TUNE_SHIFT |
imx_phy->tx_rise_tune << PHY_CTRL3_TXRISE_TUNE_SHIFT |
imx_phy->tx_preemp_amp_tune <<
PHY_CTRL3_TXPREEMP_TUNE_SHIFT |
imx_phy->comp_dis_tune;
writel(value, imx_phy->base + PHY_CTRL3);
return 0;
}
@ -415,6 +490,35 @@ static struct phy_ops imx8mq_usb_phy_ops = {
.owner = THIS_MODULE,
};
static void imx8mp_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
{
struct device *dev = imx_phy->phy->dev.parent;
if (device_property_read_u32(dev, "fsl,phy-tx-vref-tune",
&imx_phy->tx_vref_tune))
imx_phy->tx_vref_tune = PHY_TUNE_DEFAULT;
if (device_property_read_u32(dev, "fsl,phy-tx-rise-tune",
&imx_phy->tx_rise_tune))
imx_phy->tx_rise_tune = PHY_TUNE_DEFAULT;
if (device_property_read_u32(dev, "fsl,phy-tx-preemp-amp-tune",
&imx_phy->tx_preemp_amp_tune))
imx_phy->tx_preemp_amp_tune = PHY_TUNE_DEFAULT;
if (device_property_read_u32(dev, "fsl,phy-comp-dis-tune",
&imx_phy->comp_dis_tune))
imx_phy->comp_dis_tune = PHY_TUNE_DEFAULT;
if (device_property_read_u32(dev, "fsl,pcs-tx-deemph-3p5db",
&imx_phy->pcs_tx_deemph_3p5db))
imx_phy->pcs_tx_deemph_3p5db = PHY_TUNE_DEFAULT;
if (device_property_read_u32(dev, "fsl,phy-pcs-tx-swing-full",
&imx_phy->pcs_tx_swing_full))
imx_phy->pcs_tx_swing_full = PHY_TUNE_DEFAULT;
}
static int imx8mq_usb_phy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
@ -453,6 +557,8 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
power_supply_reg_notifier(&imx_phy->chg_det_nb);
}
imx8mp_get_phy_tuning_data(imx_phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);