[PATCH v3 5/6] net: phy: nxp-tja11xx: Add NXP TJA11xx PHY driver

Ramon Fried rfried.dev at gmail.com
Thu Mar 3 08:50:45 CET 2022


On Thu, Feb 17, 2022 at 4:36 PM Ariel D'Alessandro
<ariel.dalessandro at collabora.com> wrote:
>
> From: Michael Trimarchi <michael at amarulasolutions.com>
>
> Add driver for the NXP TJA1100 and TJA1101 PHYs. These PHYs are special
> BroadRReach 100BaseT1 PHYs used in automotive.
>
> Signed-off-by: Michael Trimarchi <michael at amarulasolutions.com>
> Signed-off-by: Ariel D'Alessandro <ariel.dalessandro at collabora.com>
> ---
>  drivers/net/phy/Kconfig       |   5 +
>  drivers/net/phy/Makefile      |   1 +
>  drivers/net/phy/nxp-tja11xx.c | 277 ++++++++++++++++++++++++++++++++++
>  drivers/net/phy/phy.c         |   3 +
>  include/phy.h                 |   1 +
>  5 files changed, 287 insertions(+)
>  create mode 100644 drivers/net/phy/nxp-tja11xx.c
>
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index 4f8d33ce8fd..8de6130113c 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -211,6 +211,11 @@ config PHY_NXP_C45_TJA11XX
>           Enable support for NXP C45 TJA11XX PHYs.
>           Currently supports only the TJA1103 PHY.
>
> +config PHY_NXP_TJA11XX
> +       bool "NXP TJA11XX Ethernet PHYs support"
> +       help
> +         Currently supports the NXP TJA1100 and TJA1101 PHY.
> +
>  config PHY_REALTEK
>         bool "Realtek Ethernet PHYs support"
>
> diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
> index 77f7f606215..7cfbab0b5c8 100644
> --- a/drivers/net/phy/Makefile
> +++ b/drivers/net/phy/Makefile
> @@ -24,6 +24,7 @@ obj-$(CONFIG_PHY_MICREL_KSZ90X1) += micrel_ksz90x1.o
>  obj-$(CONFIG_PHY_MESON_GXL) += meson-gxl.o
>  obj-$(CONFIG_PHY_NATSEMI) += natsemi.o
>  obj-$(CONFIG_PHY_NXP_C45_TJA11XX) += nxp-c45-tja11xx.o
> +obj-$(CONFIG_PHY_NXP_TJA11XX) += nxp-tja11xx.o
>  obj-$(CONFIG_PHY_REALTEK) += realtek.o
>  obj-$(CONFIG_PHY_SMSC) += smsc.o
>  obj-$(CONFIG_PHY_TERANETICS) += teranetics.o
> diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
> new file mode 100644
> index 00000000000..30dec5e605b
> --- /dev/null
> +++ b/drivers/net/phy/nxp-tja11xx.c
> @@ -0,0 +1,277 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* NXP TJA1100 BroadRReach PHY driver
> + *
> + * Copyright (C) 2022 Michael Trimarchi <michael at amarulasolutions.com>
> + * Copyright (C) 2022 Ariel D'Alessandro <ariel.dalessandro at collabora.com>
> + * Copyright (C) 2018 Marek Vasut <marex at denx.de>
> + */
> +
> +#include <common.h>
> +#include <linux/bitops.h>
> +#include <linux/delay.h>
> +#include <linux/iopoll.h>
> +#include <phy.h>
> +
> +#define PHY_ID_MASK                    0xfffffff0
> +#define PHY_ID_TJA1100                 0x0180dc40
> +#define PHY_ID_TJA1101                 0x0180dd00
> +
> +#define MII_ECTRL                      17
> +#define MII_ECTRL_LINK_CONTROL         BIT(15)
> +#define MII_ECTRL_POWER_MODE_MASK      GENMASK(14, 11)
> +#define MII_ECTRL_POWER_MODE_NO_CHANGE (0x0 << 11)
> +#define MII_ECTRL_POWER_MODE_NORMAL    (0x3 << 11)
> +#define MII_ECTRL_POWER_MODE_STANDBY   (0xc << 11)
> +#define MII_ECTRL_CABLE_TEST           BIT(5)
> +#define MII_ECTRL_CONFIG_EN            BIT(2)
> +#define MII_ECTRL_WAKE_REQUEST         BIT(0)
> +
> +#define MII_CFG1                       18
> +#define MII_CFG1_MASTER_SLAVE          BIT(15)
> +#define MII_CFG1_AUTO_OP               BIT(14)
> +#define MII_CFG1_SLEEP_CONFIRM         BIT(6)
> +#define MII_CFG1_LED_MODE_MASK         GENMASK(5, 4)
> +#define MII_CFG1_LED_MODE_LINKUP       0
> +#define MII_CFG1_LED_ENABLE            BIT(3)
> +
> +#define MII_CFG2                       19
> +#define MII_CFG2_SLEEP_REQUEST_TO      GENMASK(1, 0)
> +#define MII_CFG2_SLEEP_REQUEST_TO_16MS 0x3
> +
> +#define MII_INTSRC                     21
> +#define MII_INTSRC_LINK_FAIL           BIT(10)
> +#define MII_INTSRC_LINK_UP             BIT(9)
> +#define MII_INTSRC_MASK                        (MII_INTSRC_LINK_FAIL | \
> +                                        MII_INTSRC_LINK_UP)
> +#define MII_INTSRC_UV_ERR              BIT(3)
> +#define MII_INTSRC_TEMP_ERR            BIT(1)
> +
> +#define MII_INTEN                      22
> +#define MII_INTEN_LINK_FAIL            BIT(10)
> +#define MII_INTEN_LINK_UP              BIT(9)
> +#define MII_INTEN_UV_ERR               BIT(3)
> +#define MII_INTEN_TEMP_ERR             BIT(1)
> +
> +#define MII_COMMSTAT                   23
> +#define MII_COMMSTAT_LINK_UP           BIT(15)
> +#define MII_COMMSTAT_SQI_STATE         GENMASK(7, 5)
> +#define MII_COMMSTAT_SQI_MAX           7
> +
> +#define MII_GENSTAT                    24
> +#define MII_GENSTAT_PLL_LOCKED         BIT(14)
> +
> +#define MII_EXTSTAT                    25
> +#define MII_EXTSTAT_SHORT_DETECT       BIT(8)
> +#define MII_EXTSTAT_OPEN_DETECT                BIT(7)
> +#define MII_EXTSTAT_POLARITY_DETECT    BIT(6)
> +
> +#define MII_COMMCFG                    27
> +#define MII_COMMCFG_AUTO_OP            BIT(15)
> +
> +static inline int tja11xx_set_bits(struct phy_device *phydev, u32 regnum,
> +                                  u16 val)
> +{
> +       return phy_set_bits_mmd(phydev, MDIO_DEVAD_NONE, regnum, val);
> +}
> +
> +static inline int tja11xx_clear_bits(struct phy_device *phydev, u32 regnum,
> +                                    u16 val)
> +{
> +       return phy_clear_bits_mmd(phydev, MDIO_DEVAD_NONE, regnum, val);
> +}
> +
> +static inline int tja11xx_read(struct phy_device *phydev, int regnum)
> +{
> +       return phy_read(phydev, MDIO_DEVAD_NONE, regnum);
> +}
> +
> +static inline int tja11xx_modify(struct phy_device *phydev, int regnum,
> +                                u16 mask, u16 set)
> +{
> +       return phy_modify(phydev, MDIO_DEVAD_NONE, regnum, mask, set);
> +}
> +
> +static int tja11xx_check(struct phy_device *phydev, u8 reg, u16 mask, u16 set)
> +{
> +       int val;
> +
> +       return read_poll_timeout(tja11xx_read, val, (val & mask) == set, 150,
> +                                30000, phydev, reg);
> +}
> +
> +static int tja11xx_modify_check(struct phy_device *phydev, u8 reg,
> +                           u16 mask, u16 set)
> +{
> +       int ret;
> +
> +       ret = tja11xx_modify(phydev, reg, mask, set);
> +       if (ret)
> +               return ret;
> +
> +       return tja11xx_check(phydev, reg, mask, set);
> +}
> +
> +static int tja11xx_enable_reg_write(struct phy_device *phydev)
> +{
> +       return tja11xx_set_bits(phydev, MII_ECTRL, MII_ECTRL_CONFIG_EN);
> +}
> +
> +static int tja11xx_enable_link_control(struct phy_device *phydev)
> +{
> +       return tja11xx_set_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL);
> +}
> +
> +static int tja11xx_wakeup(struct phy_device *phydev)
> +{
> +       int ret;
> +
> +       ret = tja11xx_read(phydev, MII_ECTRL);
> +       if (ret < 0)
> +               return ret;
> +
> +       switch (ret & MII_ECTRL_POWER_MODE_MASK) {
> +       case MII_ECTRL_POWER_MODE_NO_CHANGE:
> +               break;
> +       case MII_ECTRL_POWER_MODE_NORMAL:
> +               ret = tja11xx_set_bits(phydev, MII_ECTRL,
> +                                      MII_ECTRL_WAKE_REQUEST);
> +               if (ret)
> +                       return ret;
> +
> +               ret = tja11xx_clear_bits(phydev, MII_ECTRL,
> +                                        MII_ECTRL_WAKE_REQUEST);
> +               if (ret)
> +                       return ret;
> +               break;
> +       case MII_ECTRL_POWER_MODE_STANDBY:
> +               ret = tja11xx_modify_check(phydev, MII_ECTRL,
> +                                          MII_ECTRL_POWER_MODE_MASK,
> +                                          MII_ECTRL_POWER_MODE_STANDBY);
> +               if (ret)
> +                       return ret;
> +
> +               ret = tja11xx_modify(phydev, MII_ECTRL,
> +                                    MII_ECTRL_POWER_MODE_MASK,
> +                                    MII_ECTRL_POWER_MODE_NORMAL);
> +               if (ret)
> +                       return ret;
> +
> +               ret = tja11xx_modify_check(phydev, MII_GENSTAT,
> +                                          MII_GENSTAT_PLL_LOCKED,
> +                                          MII_GENSTAT_PLL_LOCKED);
> +               if (ret)
> +                       return ret;
> +
> +               return tja11xx_enable_link_control(phydev);
> +       default:
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static int tja11xx_config_init(struct phy_device *phydev)
> +{
> +       int ret;
> +
> +       ret = tja11xx_enable_reg_write(phydev);
> +       if (ret)
> +               return ret;
> +
> +       phydev->autoneg = AUTONEG_DISABLE;
> +       phydev->speed = SPEED_100;
> +       phydev->duplex = DUPLEX_FULL;
> +
> +       switch (phydev->phy_id & PHY_ID_MASK) {
> +       case PHY_ID_TJA1100:
> +               ret = tja11xx_modify(phydev, MII_CFG1,
> +                                    MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_MASK |
> +                                    MII_CFG1_LED_ENABLE,
> +                                    MII_CFG1_AUTO_OP |
> +                                    MII_CFG1_LED_MODE_LINKUP |
> +                                    MII_CFG1_LED_ENABLE);
> +               if (ret)
> +                       return ret;
> +               break;
> +       case PHY_ID_TJA1101:
> +               ret = tja11xx_set_bits(phydev, MII_COMMCFG,
> +                                      MII_COMMCFG_AUTO_OP);
> +               if (ret)
> +                       return ret;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       ret = tja11xx_clear_bits(phydev, MII_CFG1, MII_CFG1_SLEEP_CONFIRM);
> +       if (ret)
> +               return ret;
> +
> +       ret = tja11xx_modify(phydev, MII_CFG2, MII_CFG2_SLEEP_REQUEST_TO,
> +                            MII_CFG2_SLEEP_REQUEST_TO_16MS);
> +       if (ret)
> +               return ret;
> +
> +       ret = tja11xx_wakeup(phydev);
> +       if (ret < 0)
> +               return ret;
> +
> +       /* ACK interrupts by reading the status register */
> +       ret = tja11xx_read(phydev, MII_INTSRC);
> +       if (ret < 0)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static int tja11xx_startup(struct phy_device *phydev)
> +{
> +       int ret;
> +
> +       ret = genphy_update_link(phydev);
> +       if (ret)
> +               return ret;
> +
> +       ret = tja11xx_read(phydev, MII_CFG1);
> +       if (ret < 0)
> +               return ret;
> +
> +       if (phydev->link) {
> +               ret = tja11xx_read(phydev, MII_COMMSTAT);
> +               if (ret < 0)
> +                       return ret;
> +
> +               if (!(ret & MII_COMMSTAT_LINK_UP))
> +                       phydev->link = 0;
> +       }
> +
> +       return 0;
> +}
> +
> +static struct phy_driver TJA1100_driver = {
> +       .name = "NXP TJA1100",
> +       .uid = PHY_ID_TJA1100,
> +       .mask = PHY_ID_MASK,
> +       .features = PHY_BASIC_FEATURES,
> +       .config = &tja11xx_config_init,
> +       .startup = &tja11xx_startup,
> +       .shutdown = &genphy_shutdown,
> +};
> +
> +static struct phy_driver TJA1101_driver = {
> +       .name = "NXP TJA1101",
> +       .uid = PHY_ID_TJA1101,
> +       .mask = PHY_ID_MASK,
> +       .features = PHY_BASIC_FEATURES,
> +       .config = &tja11xx_config_init,
> +       .startup = &tja11xx_startup,
> +       .shutdown = &genphy_shutdown,
> +};
> +
> +int phy_nxp_tja11xx_init(void)
> +{
> +       phy_register(&TJA1100_driver);
> +       phy_register(&TJA1101_driver);
> +
> +       return 0;
> +}
> diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
> index b73361d87d9..af55faf55de 100644
> --- a/drivers/net/phy/phy.c
> +++ b/drivers/net/phy/phy.c
> @@ -532,6 +532,9 @@ int phy_init(void)
>  #ifdef CONFIG_NXP_C45_TJA11XX_PHY
>         phy_nxp_c45_tja11xx_init();
>  #endif
> +#ifdef CONFIG_PHY_NXP_TJA11XX
> +       phy_nxp_tja11xx_init();
> +#endif
>  #ifdef CONFIG_PHY_REALTEK
>         phy_realtek_init();
>  #endif
> diff --git a/include/phy.h b/include/phy.h
> index 2dd2e02ab5d..bb03c31d851 100644
> --- a/include/phy.h
> +++ b/include/phy.h
> @@ -530,6 +530,7 @@ int phy_micrel_ksz90x1_init(void);
>  int phy_meson_gxl_init(void);
>  int phy_natsemi_init(void);
>  int phy_nxp_c45_tja11xx_init(void);
> +int phy_nxp_tja11xx_init(void);
>  int phy_realtek_init(void);
>  int phy_smsc_init(void);
>  int phy_teranetics_init(void);
> --
> 2.34.1
>
Reviewed-by: Ramon Fried <rfried.dev at gmail.com>


More information about the U-Boot mailing list