[PATCH] net: ksz9477: add support for KSZ9893 GbE switch

Ramon Fried rfried.dev at gmail.com
Sat Jul 22 11:00:42 CEST 2023


On Thu, Jun 29, 2023 at 1:18 AM Karsten Wiese
<karsten.wiese at protechna.com> wrote:
>
> Copy and tweak the required code from the linux kernel.
> Only the KSZ9893 has been tested.
>
> Signed-off-by: Karsten Wiese <karsten.wiese at protechna.com>
>
> ---
>  drivers/net/ksz9477.c | 103 ++++++++++++++++++++++++++++++++++++------
>  1 file changed, 89 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c
> index 6b59b5fcd2..43baa69961 100644
> --- a/drivers/net/ksz9477.c
> +++ b/drivers/net/ksz9477.c
> @@ -16,6 +16,10 @@
>
>  #include <asm-generic/gpio.h>
>
> +/* Used with variable features to indicate capabilities. */
> +#define NEW_XMII                       BIT(1)
> +#define IS_9893                                BIT(2)
> +
>  /* Global registers */
>
>  /* Chip ID */
> @@ -41,6 +45,13 @@
>  #define PORT_RMII_SEL                  0x1
>  #define PORT_GMII_SEL                  0x2
>  #define PORT_MII_SEL                   0x3
> +/* S1 */
> +#define PORT_MII_1000MBIT_S1           BIT(6)
> +/* S1 */
> +#define PORT_MII_SEL_S1                        0x0
> +#define PORT_RMII_SEL_S1               0x1
> +#define PORT_GMII_SEL_S1               0x2
> +#define PORT_RGMII_SEL_S1              0x3
>
>  /* Port MSTP State Register */
>  #define REG_PORT_MSTP_STATE            0x0b04
> @@ -62,6 +73,8 @@
>
>  struct ksz_dsa_priv {
>         struct udevice *dev;
> +
> +       u32 features;                   /* chip specific features */
>  };
>
>  static inline int ksz_read8(struct udevice *dev, u32 reg, u8 *val)
> @@ -284,6 +297,60 @@ U_BOOT_DRIVER(ksz_mdio) = {
>         .plat_auto      = sizeof(struct mdio_perdev_priv),
>  };
>
> +static void ksz9477_set_gbit(struct ksz_dsa_priv *priv, bool gbit, u8 *data)
> +{
> +       if (priv->features & NEW_XMII) {
> +               if (gbit)
> +                       *data &= ~PORT_MII_NOT_1GBIT;
> +               else
> +                       *data |= PORT_MII_NOT_1GBIT;
> +       } else {
> +               if (gbit)
> +                       *data |= PORT_MII_1000MBIT_S1;
> +               else
> +                       *data &= ~PORT_MII_1000MBIT_S1;
> +       }
> +}
> +
> +static void ksz9477_set_xmii(struct ksz_dsa_priv *priv, int mode, u8 *data)
> +{
> +       u8 xmii;
> +
> +       if (priv->features & NEW_XMII) {
> +               switch (mode) {
> +               case 0:
> +                       xmii = PORT_MII_SEL;
> +                       break;
> +               case 1:
> +                       xmii = PORT_RMII_SEL;
> +                       break;
> +               case 2:
> +                       xmii = PORT_GMII_SEL;
> +                       break;
> +               default:
> +                       xmii = PORT_RGMII_SEL;
> +                       break;
> +               }
> +       } else {
> +               switch (mode) {
> +               case 0:
> +                       xmii = PORT_MII_SEL_S1;
> +                       break;
> +               case 1:
> +                       xmii = PORT_RMII_SEL_S1;
> +                       break;
> +               case 2:
> +                       xmii = PORT_GMII_SEL_S1;
> +                       break;
> +               default:
> +                       xmii = PORT_RGMII_SEL_S1;
> +                       break;
> +               }
> +       }
> +       *data &= ~PORT_MII_SEL_M;
> +       *data |= xmii;
> +}
> +
>  static int ksz_port_setup(struct udevice *dev, int port,
>                           phy_interface_t interface)
>  {
> @@ -293,9 +360,11 @@ static int ksz_port_setup(struct udevice *dev, int port,
>         dev_dbg(dev, "%s P%d %s\n", __func__, port + 1,
>                 (port == pdata->cpu_port) ? "cpu" : "");
>
> +       struct ksz_dsa_priv *priv = dev_get_priv(dev);
>         if (port != pdata->cpu_port) {
> -               /* phy port: config errata and leds */
> -               ksz_phy_errata_setup(dev, port);
> +               if (priv->features & NEW_XMII)
> +                       /* phy port: config errata and leds */
> +                       ksz_phy_errata_setup(dev, port);
>         } else {
>                 /* cpu port: configure MAC interface mode */
>                 ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8);
> @@ -303,24 +372,20 @@ static int ksz_port_setup(struct udevice *dev, int port,
>                         phy_string_for_interface(interface));
>                 switch (interface) {
>                 case PHY_INTERFACE_MODE_MII:
> -                       data8 &= ~PORT_MII_SEL_M;
> -                       data8 |= PORT_MII_SEL;
> -                       data8 |= PORT_MII_NOT_1GBIT;
> +                       ksz9477_set_xmii(priv, 0, &data8);
> +                       ksz9477_set_gbit(priv, false, &data8);
>                         break;
>                 case PHY_INTERFACE_MODE_RMII:
> -                       data8 &= ~PORT_MII_SEL_M;
> -                       data8 |= PORT_RMII_SEL;
> -                       data8 |= PORT_MII_NOT_1GBIT;
> +                       ksz9477_set_xmii(priv, 1, &data8);
> +                       ksz9477_set_gbit(priv, false, &data8);
>                         break;
>                 case PHY_INTERFACE_MODE_GMII:
> -                       data8 &= ~PORT_MII_SEL_M;
> -                       data8 |= PORT_GMII_SEL;
> -                       data8 &= ~PORT_MII_NOT_1GBIT;
> +                       ksz9477_set_xmii(priv, 2, &data8);
> +                       ksz9477_set_gbit(priv, true, &data8);
>                         break;
>                 default:
> -                       data8 &= ~PORT_MII_SEL_M;
> -                       data8 |= PORT_RGMII_SEL;
> -                       data8 &= ~PORT_MII_NOT_1GBIT;
> +                       ksz9477_set_xmii(priv, 3, &data8);
> +                       ksz9477_set_gbit(priv, true, &data8);
>                         data8 &= ~PORT_RGMII_ID_IG_ENABLE;
>                         data8 &= ~PORT_RGMII_ID_EG_ENABLE;
>                         if (interface == PHY_INTERFACE_MODE_RGMII_ID ||
> @@ -329,6 +394,8 @@ static int ksz_port_setup(struct udevice *dev, int port,
>                         if (interface == PHY_INTERFACE_MODE_RGMII_ID ||
>                             interface == PHY_INTERFACE_MODE_RGMII_TXID)
>                                 data8 |= PORT_RGMII_ID_EG_ENABLE;
> +                       if (priv->features & IS_9893)
> +                               data8 &= ~PORT_MII_MAC_MODE;
>                         break;
>                 }
>                 ksz_write8(dev, PORT_CTRL_ADDR(port, REG_PORT_XMII_CTRL_1), data8);
> @@ -479,10 +546,17 @@ static int ksz_i2c_probe(struct udevice *dev)
>         case 0x00989700:
>                 puts("KSZ9897S: ");
>                 break;
> +       case 0x00989300:
> +               puts("KSZ9893R: ");
> +               break;
>         default:
>                 dev_err(dev, "invalid chip id: 0x%08x\n", id);
>                 return -EINVAL;
>         }
> +       if ((id & 0xf00) == 0x300)
> +               priv->features |= IS_9893;
> +       else
> +               priv->features |= NEW_XMII;
>
>         /* probe mdio bus */
>         ret = ksz_probe_mdio(dev);
> @@ -503,6 +577,7 @@ static const struct udevice_id ksz_i2c_ids[] = {
>         { .compatible = "microchip,ksz9897" },
>         { .compatible = "microchip,ksz9477" },
>         { .compatible = "microchip,ksz9567" },
> +       { .compatible = "microchip,ksz9893" },
>         { }
>  };
>
> --
> 2.25.1
>
>
Reviewed-by: Ramon Fried <rfried.dev at gmail.com>


More information about the U-Boot mailing list