On Tue, Aug 16, 2016 at 06:31:48PM -0400, Jaret Cantu wrote:
> The TX settings can be calibrated for particular hardware.  The
> phy is reset by Linux, so this cannot be handled by the bootloader.
> 
> The TRM mentions that the maximum resistance should be used for the
> DN/DP calibration in order to pass USB certification.
> 
> The values for the TX registers are poorly described in the TRM.
> The meanings of the register values were taken from another
> NXP-provided document:
> https://community.nxp.com/message/566147#comment-566912
> 
> Signed-off-by: Jaret Cantu <jaret.ca...@timesys.com>
> ---
> v4. Corrected tx-d-cal register value by rounding up.
>     Changed Freescale web site reference to NXP.
> 
> v3. Added unit suffix (-ohms) to tx-cal-45-d*
> 
> v2. Copying devicetree list
>     Removed prettifying extra whitespace
>     Removed unnecessary register rewrite on resume
>     Use min and max constants for clarity
> 
>  .../devicetree/bindings/phy/mxs-usb-phy.txt        |   10 ++++
>  drivers/usb/phy/phy-mxs-usb.c                      |   61 
> ++++++++++++++++++++
>  2 files changed, 71 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt 
> b/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt
> index 379b84a..1d25b04 100644
> --- a/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt
> +++ b/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt
> @@ -12,6 +12,16 @@ Required properties:
>  - interrupts: Should contain phy interrupt
>  - fsl,anatop: phandle for anatop register, it is only for imx6 SoC series
>  
> +Optional properties:
> +- fsl,tx-cal-45-dn-ohms: Integer [30-55]. Resistance (in ohms) of switchable
> +  high-speed trimming resistor connected in parallel with the 45 ohm resistor
> +  that terminates the DN output signal. Default: 45
> +- fsl,tx-cal-45-dp-ohms: Integer [30-55]. Resistance (in ohms) of switchable
> +  high-speed trimming resistor connected in parallel with the 45 ohm resistor
> +  that terminates the DP output signal. Default: 45
> +- fsl,tx-d-cal: Integer [79-119]. Current trimming value (as a percentage) of
> +  the 17.78mA TX reference current. Default: 100
> +
>  Example:
>  usbphy1: usbphy@020c9000 {
>       compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
> diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
> index 00bfea0..0e2f1a3 100644
> --- a/drivers/usb/phy/phy-mxs-usb.c
> +++ b/drivers/usb/phy/phy-mxs-usb.c
> @@ -27,6 +27,7 @@
>  #define DRIVER_NAME "mxs_phy"
>  
>  #define HW_USBPHY_PWD                                0x00
> +#define HW_USBPHY_TX                         0x10
>  #define HW_USBPHY_CTRL                               0x30
>  #define HW_USBPHY_CTRL_SET                   0x34
>  #define HW_USBPHY_CTRL_CLR                   0x38
> @@ -38,6 +39,10 @@
>  #define HW_USBPHY_IP_SET                     0x94
>  #define HW_USBPHY_IP_CLR                     0x98
>  
> +#define GM_USBPHY_TX_TXCAL45DP(x)            (((x) & 0xf) << 16)
> +#define GM_USBPHY_TX_TXCAL45DN(x)            (((x) & 0xf) << 8)
> +#define GM_USBPHY_TX_D_CAL(x)                (((x) & 0xf) << 0)
> +
>  #define BM_USBPHY_CTRL_SFTRST                        BIT(31)
>  #define BM_USBPHY_CTRL_CLKGATE                       BIT(30)
>  #define BM_USBPHY_CTRL_OTG_ID_VALUE          BIT(27)
> @@ -115,6 +120,12 @@
>   */
>  #define MXS_PHY_NEED_IP_FIX                  BIT(3)
>  
> +/* Minimum and maximum values for device tree entries */
> +#define MXS_PHY_TX_CAL45_MIN                 30
> +#define MXS_PHY_TX_CAL45_MAX                 55
> +#define MXS_PHY_TX_D_CAL_MIN                 79
> +#define MXS_PHY_TX_D_CAL_MAX                 119
> +
>  struct mxs_phy_data {
>       unsigned int flags;
>  };
> @@ -164,6 +175,8 @@ struct mxs_phy {
>       const struct mxs_phy_data *data;
>       struct regmap *regmap_anatop;
>       int port_id;
> +     u32 tx_reg_set;
> +     u32 tx_reg_mask;
>  };
>  
>  static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy)
> @@ -185,6 +198,20 @@ static void mxs_phy_clock_switch_delay(void)
>       usleep_range(300, 400);
>  }
>  
> +static void mxs_phy_tx_init(struct mxs_phy *mxs_phy)
> +{
> +     void __iomem *base = mxs_phy->phy.io_priv;
> +     u32 phytx;
> +
> +     /* Update TX register if there is anything to write */
> +     if (mxs_phy->tx_reg_mask) {
> +             phytx = readl(base + HW_USBPHY_TX);
> +             phytx &= ~mxs_phy->tx_reg_mask;
> +             phytx |= mxs_phy->tx_reg_set;
> +             writel(phytx, base + HW_USBPHY_TX);
> +     }
> +}
> +
>  static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
>  {
>       int ret;
> @@ -214,6 +241,8 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
>       if (mxs_phy->data->flags & MXS_PHY_NEED_IP_FIX)
>               writel(BM_USBPHY_IP_FIX, base + HW_USBPHY_IP_SET);
>  
> +     mxs_phy_tx_init(mxs_phy);
> +
>       return 0;
>  }
>  
> @@ -459,6 +488,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
>       int ret;
>       const struct of_device_id *of_id;
>       struct device_node *np = pdev->dev.of_node;
> +     u32 val;
>  
>       of_id = of_match_device(mxs_phy_dt_ids, &pdev->dev);
>       if (!of_id)
> @@ -491,6 +521,37 @@ static int mxs_phy_probe(struct platform_device *pdev)
>               }
>       }
>  
> +     /* Precompute which bits of the TX register are to be updated, if any */
> +     if (!of_property_read_u32(np, "fsl,tx-cal-45-dn-ohms", &val) &&
> +         val >= MXS_PHY_TX_CAL45_MIN && val <= MXS_PHY_TX_CAL45_MAX) {
> +             /* Scale to a 4-bit value */
> +             val = (MXS_PHY_TX_CAL45_MAX - val) * 0xF
> +                     / (MXS_PHY_TX_CAL45_MAX - MXS_PHY_TX_CAL45_MIN);
> +             mxs_phy->tx_reg_mask |= GM_USBPHY_TX_TXCAL45DN(~0);
> +             mxs_phy->tx_reg_set  |= GM_USBPHY_TX_TXCAL45DN(val);
> +     }
> +
> +     if (!of_property_read_u32(np, "fsl,tx-cal-45-dp-ohms", &val) &&
> +         val >= MXS_PHY_TX_CAL45_MIN && val <= MXS_PHY_TX_CAL45_MAX) {
> +             /* Scale to a 4-bit value. */
> +             val = (MXS_PHY_TX_CAL45_MAX - val) * 0xF
> +                     / (MXS_PHY_TX_CAL45_MAX - MXS_PHY_TX_CAL45_MIN);
> +             mxs_phy->tx_reg_mask |= GM_USBPHY_TX_TXCAL45DP(~0);
> +             mxs_phy->tx_reg_set  |= GM_USBPHY_TX_TXCAL45DP(val);
> +     }
> +
> +     if (!of_property_read_u32(np, "fsl,tx-d-cal", &val) &&
> +         val >= MXS_PHY_TX_D_CAL_MIN && val <= MXS_PHY_TX_D_CAL_MAX) {
> +             /* Scale to a 4-bit value.  Round up the values and heavily
> +              * weight the rounding by adding 2/3 of the denominator.
> +              */
> +             val = ((MXS_PHY_TX_D_CAL_MAX - val) * 0xF
> +                     + (MXS_PHY_TX_D_CAL_MAX - MXS_PHY_TX_D_CAL_MIN) * 2/3)
> +                     / (MXS_PHY_TX_D_CAL_MAX - MXS_PHY_TX_D_CAL_MIN);
> +             mxs_phy->tx_reg_mask |= GM_USBPHY_TX_D_CAL(~0);
> +             mxs_phy->tx_reg_set  |= GM_USBPHY_TX_D_CAL(val);
> +     }
> +
>       ret = of_alias_get_id(np, "usbphy");
>       if (ret < 0)
>               dev_dbg(&pdev->dev, "failed to get alias id, errno %d\n", ret);
> -- 

Acked-by: Peter Chen <peter.c...@nxp.com>

-- 

Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to