[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