[U-Boot] [PATCH 1/3] net: phy: mscc: add support for VSC8584 PHY

Joe Hershberger joe.hershberger at ni.com
Mon Oct 22 21:52:39 UTC 2018


On Fri, Sep 14, 2018 at 7:50 AM Quentin Schulz
<quentin.schulz at bootlin.com> wrote:
>
> The VSC8584 PHY is a 4-port PHY that is 10/100/1000BASE-T, 100BASE-FX,
> 1000BASE-X and triple-speed copper SFP capable, can communicate with the
> MAC via SGMII, QSGMII or 1000BASE-X, supports downshifting and can set
> the blinking pattern of each of its 4 LEDs, supports hardware offloading
> of MACsec and supports SyncE as well as HP Auto-MDIX detection.
>
> This adds support for 10/100/1000BASE-T and SGMII/QSGMII link with the
> MAC.
>
> The VSC8584 has also an internal Intel 8051 microcontroller whose
> firmware needs to be patched when the PHY is reset. If the 8051's
> firmware has the expected CRC, its patching can be skipped. The
> microcontroller can be accessed from any port of the PHY, though the CRC
> function can only be done through the PHY that is the base PHY of the
> package (internal address 0) due to a limitation of the firmware.
>
> The GPIO register bank is a set of registers that are common to all PHYs
> in the package. So any modification in any register of this bank affects
> all PHYs of the package.
>
> The revA of the VSC8584 PHY (which is not and will not be publicly
> released) should NOT patch the firmware of the microcontroller or it'll
> make things worse, the easiest way is just to not support it.
>
> Signed-off-by: Quentin Schulz <quentin.schulz at bootlin.com>
> ---
>  drivers/net/phy/mscc.c | 542 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 542 insertions(+)
>
> diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
> index 439f5e3c5c..0e54fe0eff 100644
> --- a/drivers/net/phy/mscc.c
> +++ b/drivers/net/phy/mscc.c
> @@ -11,12 +11,15 @@
>
>  #include <miiphy.h>
>  #include <bitfield.h>
> +#include <time.h>
> +#include <linux/delay.h>
>
>  /* Microsemi PHY ID's */
>  #define PHY_ID_VSC8530                  0x00070560
>  #define PHY_ID_VSC8531                  0x00070570
>  #define PHY_ID_VSC8540                  0x00070760
>  #define PHY_ID_VSC8541                  0x00070770
> +#define PHY_ID_VSC8584                  0x000707c0
>
>  /* Microsemi VSC85xx PHY Register Pages */
>  #define MSCC_EXT_PAGE_ACCESS            31     /* Page Access Register */
> @@ -29,6 +32,14 @@
>  #define MSCC_PHY_PAGE_TEST             0x2A30 /* TEST Page registers */
>  #define MSCC_PHY_PAGE_TR               0x52B5 /* Token Ring Page registers */
>
> +/* Std Page Register 18 */
> +#define MSCC_PHY_BYPASS_CONTROL           18
> +#define PARALLEL_DET_IGNORE_ADVERTISED    0x0008
> +
> +/* Std Page Register 22 */
> +#define MSCC_PHY_EXT_CNTL_STATUS          22
> +#define SMI_BROADCAST_WR_EN              0x0001
> +
>  /* Std Page Register 28 - PHY AUX Control/Status */
>  #define MIIM_AUX_CNTRL_STAT_REG                28
>  #define MIIM_AUX_CNTRL_STAT_ACTIPHY_TO (0x0004)
> @@ -47,6 +58,37 @@
>  #define MAC_IF_SELECTION_RGMII         (2)
>  #define MAC_IF_SELECTION_POS           (11)
>  #define MAC_IF_SELECTION_WIDTH         (2)
> +#define VSC8584_MAC_IF_SELECTION_MASK     0x1000
> +#define VSC8584_MAC_IF_SELECTION_SGMII    0
> +#define VSC8584_MAC_IF_SELECTION_1000BASEX 1
> +#define VSC8584_MAC_IF_SELECTION_POS      12
> +#define MEDIA_OP_MODE_MASK               0x0700

Please use GENMASK() or BIT() for masks.

> +#define MEDIA_OP_MODE_COPPER             0
> +#define MEDIA_OP_MODE_SERDES             1
> +#define MEDIA_OP_MODE_1000BASEX                  2
> +#define MEDIA_OP_MODE_100BASEFX                  3
> +#define MEDIA_OP_MODE_AMS_COPPER_SERDES          5
> +#define MEDIA_OP_MODE_AMS_COPPER_1000BASEX     6
> +#define MEDIA_OP_MODE_AMS_COPPER_100BASEFX     7
> +#define MEDIA_OP_MODE_POS                8
> +
> +/* Extended Page 1 Register 20E1 */
> +#define MSCC_PHY_ACTIPHY_CNTL            20
> +#define PHY_ADDR_REVERSED                0x0200
> +
> +/* Extended Page 1 Register 23E1 */
> +
> +#define MSCC_PHY_EXT_PHY_CNTL_4           23
> +#define PHY_CNTL_4_ADDR_POS              11
> +
> +/* Extended Page 1 Register 25E1 */
> +#define MSCC_PHY_VERIPHY_CNTL_2                25
> +
> +/* Extended Page 1 Register 26E1 */
> +#define MSCC_PHY_VERIPHY_CNTL_3                26
> +
> +/* Extended Page 2 Register 16E2 */
> +#define MSCC_PHY_CU_PMD_TX_CNTL         16
>
>  /* Extended Page 2 Register 20E2 */
>  #define MSCC_PHY_RGMII_CNTL_REG                20
> @@ -72,6 +114,74 @@
>  #define RMII_CLK_OUT_ENABLE_WIDTH      (1)
>  #define RMII_CLK_OUT_ENABLE_MASK       (0x10)
>
> +/* Extended Page 3 Register 22E3 */
> +#define MSCC_PHY_SERDES_TX_CRC_ERR_CNT 22
> +
> +/* Extended page GPIO register 00G */
> +#define MSCC_DW8051_CNTL_STATUS                0
> +#define MICRO_NSOFT_RESET              0x8000

Bit definitions such as these should use BIT().

> +#define RUN_FROM_INT_ROM               0x4000
> +#define AUTOINC_ADDR                   0x2000
> +#define PATCH_RAM_CLK                  0x1000
> +#define MICRO_PATCH_EN                 0x0080
> +#define DW8051_CLK_EN                  0x0010
> +#define MICRO_CLK_EN                   0x0008
> +#define MICRO_CLK_DIVIDE(x)            ((x) >> 1)
> +
> +/* Extended page GPIO register 09G */
> +#define MSCC_TRAP_ROM_ADDR(x)          ((x) * 2 + 1)
> +
> +/* Extended page GPIO register 10G */
> +#define MSCC_PATCH_RAM_ADDR(x)         (((x) + 1) * 2)
> +
> +/* Extended page GPIO register 11G */
> +#define MSCC_INT_MEM_ADDR              11
> +
> +/* Extended page GPIO register 12G */
> +#define MSCC_INT_MEM_CNTL              12
> +#define READ_SFR                       0x6000
> +#define READ_PRAM                      0x4000
> +#define READ_ROM                       0x2000
> +#define READ_RAM                       0x0000
> +#define INT_MEM_WRITE_EN               0x1000
> +#define EN_PATCH_RAM_TRAP_ADDR(x)      (0x0100 << ((x) - 1))
> +#define INT_MEM_DATA_M                 0x00ff
> +#define INT_MEM_DATA(x)                        (INT_MEM_DATA_M & (x))
> +
> +/* Extended page GPIO register 18G */
> +#define MSCC_PHY_PROC_CMD                18
> +#define PROC_CMD_NCOMPLETED              0x8000
> +#define PROC_CMD_FAILED                          0x4000
> +#define PROC_CMD_SGMII_PORT(x)           ((x) << 8)
> +#define PROC_CMD_FIBER_PORT(x)           (0x0100 << (x) % 4)
> +#define PROC_CMD_QSGMII_PORT             0x0c00
> +#define PROC_CMD_RST_CONF_PORT           0x0080
> +#define PROC_CMD_RECONF_PORT             0x0000
> +#define PROC_CMD_READ_MOD_WRITE_PORT     0x0040
> +#define PROC_CMD_WRITE                   0x0040
> +#define PROC_CMD_READ                    0x0000
> +#define PROC_CMD_FIBER_DISABLE           0x0020
> +#define PROC_CMD_FIBER_100BASE_FX        0x0010
> +#define PROC_CMD_FIBER_1000BASE_X        0x0000
> +#define PROC_CMD_SGMII_MAC               0x0030
> +#define PROC_CMD_QSGMII_MAC              0x0020
> +#define PROC_CMD_NO_MAC_CONF             0x0000
> +#define PROC_CMD_NOP                     0x000f
> +#define PROC_CMD_CRC16                   0x0008
> +#define PROC_CMD_FIBER_MEDIA_CONF        0x0001
> +#define PROC_CMD_MCB_ACCESS_MAC_CONF     0x0000
> +#define PROC_CMD_NCOMPLETED_TIMEOUT_MS    500
> +
> +/* Extended page GPIO register 19G */
> +#define MSCC_PHY_MAC_CFG_FASTLINK        19
> +#define MAC_CFG_MASK                     0xc000
> +#define MAC_CFG_SGMII                    0x0000
> +#define MAC_CFG_QSGMII                   0x4000
> +
> +/* Test Registers */
> +#define MSCC_PHY_TEST_PAGE_5           5
> +#define MSCC_PHY_TEST_PAGE_8           8
> +
>  /* Token Ring Page 0x52B5 Registers */
>  #define MSCC_PHY_REG_TR_ADDR_16                16
>  #define MSCC_PHY_REG_TR_DATA_17                17
> @@ -110,6 +220,12 @@
>  #define MSCC_PHY_RESET_TIMEOUT         (100)
>  #define MSCC_PHY_MICRO_TIMEOUT         (500)
>
> +#define VSC8584_REVB           0x0001
> +#define MSCC_DEV_REV_MASK      GENMASK(3, 0)
> +
> +#define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR        0xe800
> +#define MSCC_VSC8584_REVB_INT8051_FW_CRC       0xfb48
> +
>  /* RGMII/GMII Clock Delay (Skew) Options */ enum vsc_phy_rgmii_skew {
>         VSC_PHY_RGMII_DELAY_200_PS,
>         VSC_PHY_RGMII_DELAY_800_PS,
> @@ -133,6 +249,331 @@ vsc_phy_clk_slew {
>         VSC_PHY_CLK_SLEW_RATE_7,
>  };
>
> +static void vsc8584_csr_write(struct mii_dev *bus, int phy0, u16 addr, u32 val)
> +{
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18,
> +                  val >> 16);
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17,
> +                  val & GENMASK(15, 0));
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
> +                  MSCC_PHY_TR_16_WRITE | addr);
> +}
> +
> +static int vsc8584_cmd(struct mii_dev *bus, int phy, u16 val)
> +{
> +       unsigned long deadline;
> +       u16 reg_val;
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_GPIO);
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_PROC_CMD,
> +                  PROC_CMD_NCOMPLETED | val);
> +
> +       deadline = timer_get_us() + PROC_CMD_NCOMPLETED_TIMEOUT_MS * 1000;
> +       do {
> +               reg_val = bus->read(bus, phy, MDIO_DEVAD_NONE,
> +                                   MSCC_PHY_PROC_CMD);
> +       } while (timer_get_us() <= deadline &&
> +                (reg_val & PROC_CMD_NCOMPLETED) &&
> +                !(reg_val & PROC_CMD_FAILED));
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_STD);
> +
> +       if (reg_val & PROC_CMD_FAILED)
> +               return -EIO;
> +       if (reg_val & PROC_CMD_NCOMPLETED)
> +               return -ETIMEDOUT;
> +
> +       return 0;
> +}
> +
> +static int vsc8584_micro_deassert_reset(struct mii_dev *bus, int phy,
> +                                       bool patch_en)
> +{
> +       u32 enable, release;
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_GPIO);
> +
> +       enable = RUN_FROM_INT_ROM | MICRO_CLK_EN | DW8051_CLK_EN;
> +       release = MICRO_NSOFT_RESET | RUN_FROM_INT_ROM | DW8051_CLK_EN |
> +               MICRO_CLK_EN;
> +
> +       if (patch_en) {
> +               enable |= MICRO_PATCH_EN;
> +               release |= MICRO_PATCH_EN;
> +
> +               /* Clear all patches */
> +               bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL,
> +                          READ_RAM);
> +       }
> +
> +       /* Enable 8051 Micro clock; CLEAR/SET patch present; disable PRAM clock

Please correct the comment style... "/*" on its own line got
multi-line comments.

> +        * override and addr. auto-incr; operate at 125 MHz
> +        */
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS, enable);
> +       /* Release 8051 Micro SW reset */
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS, release);
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_STD);
> +
> +       return 0;
> +}
> +
> +static int vsc8584_micro_assert_reset(struct mii_dev *bus, int phy)
> +{
> +       int ret;
> +       u16 reg;
> +
> +       ret = vsc8584_cmd(bus, phy, PROC_CMD_NOP);
> +       if (ret)
> +               return ret;
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_GPIO);
> +
> +       reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL);
> +       reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL, reg);
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_TRAP_ROM_ADDR(4), 0x005b);
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PATCH_RAM_ADDR(4), 0x005b);
> +
> +       reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL);
> +       reg |= EN_PATCH_RAM_TRAP_ADDR(4);
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL, reg);
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_PROC_CMD, PROC_CMD_NOP);
> +
> +       reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS);
> +       reg &= ~MICRO_NSOFT_RESET;
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS, reg);
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_PROC_CMD,
> +                  PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_SGMII_PORT(0) |
> +                  PROC_CMD_NO_MAC_CONF | PROC_CMD_READ);
> +
> +       reg = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL);
> +       reg &= ~EN_PATCH_RAM_TRAP_ADDR(4);
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL, reg);
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_STD);
> +
> +       return 0;
> +}
> +
> +static const u8 fw_patch_vsc8584[] = {
> +       0xe8, 0x59, 0x02, 0xe8, 0x12, 0x02, 0xe8, 0x42, 0x02, 0xe8, 0x5a, 0x02,
> +       0xe8, 0x5b, 0x02, 0xe8, 0x5c, 0xe5, 0x69, 0x54, 0x0f, 0x24, 0xf7, 0x60,
> +       0x27, 0x24, 0xfc, 0x60, 0x23, 0x24, 0x08, 0x70, 0x14, 0xe5, 0x69, 0xae,
> +       0x68, 0x78, 0x04, 0xce, 0xa2, 0xe7, 0x13, 0xce, 0x13, 0xd8, 0xf8, 0x7e,
> +       0x00, 0x54, 0x0f, 0x80, 0x00, 0x7b, 0x01, 0x7a, 0x00, 0x7d, 0xee, 0x7f,
> +       0x92, 0x12, 0x50, 0xee, 0x22, 0xe4, 0xf5, 0x10, 0x85, 0x10, 0xfb, 0x7d,
> +       0x1c, 0xe4, 0xff, 0x12, 0x59, 0xea, 0x05, 0x10, 0xe5, 0x10, 0xc3, 0x94,
> +       0x04, 0x40, 0xed, 0x22, 0x22, 0x22, 0x22, 0x22,
> +};
> +
> +static int vsc8584_get_fw_crc(struct mii_dev *bus, int phy, u16 start,
> +                             u16 *crc, const u8 *fw_patch, int fw_size)
> +{
> +       int ret;
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_EXT1);
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_VERIPHY_CNTL_2, start);
> +       // Add one byte to size for the one added by the patch_fw function

Please use /* */ style comments.

> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_VERIPHY_CNTL_3,
> +                  fw_size + 1);
> +
> +       ret = vsc8584_cmd(bus, phy, PROC_CMD_CRC16);
> +       if (ret)
> +               goto out;
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_EXT1);
> +
> +       *crc = bus->read(bus, phy, MDIO_DEVAD_NONE, MSCC_PHY_VERIPHY_CNTL_2);
> +
> +out:
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_STD);
> +
> +       return ret;
> +}
> +
> +static int vsc8584_patch_fw(struct mii_dev *bus, int phy, const u8 *fw_patch,
> +                           int fw_size)
> +{
> +       int i, ret;
> +
> +       ret = vsc8584_micro_assert_reset(bus, phy);
> +       if (ret) {
> +               pr_err("%s: failed to assert reset of micro\n", __func__);
> +               return ret;
> +       }
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_GPIO);
> +
> +       /*
> +        * Hold 8051 Micro in SW Reset, Enable auto incr address and patch clock
> +        * Disable the 8051 Micro clock
> +        */
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_DW8051_CNTL_STATUS,
> +                  RUN_FROM_INT_ROM | AUTOINC_ADDR | PATCH_RAM_CLK |
> +                  MICRO_CLK_EN | MICRO_CLK_DIVIDE(2));
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL, READ_PRAM |
> +                  INT_MEM_WRITE_EN | INT_MEM_DATA(2));
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_ADDR, 0x0000);
> +
> +       for (i = 0; i < fw_size; i++)
> +               bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL,
> +                          READ_PRAM | INT_MEM_WRITE_EN | fw_patch[i]);
> +
> +       /* Clear internal memory access */
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_INT_MEM_CNTL, READ_RAM);
> +
> +       bus->write(bus, phy, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_STD);
> +
> +       return 0;
> +}
> +
> +static int vsc8584_config_pre_init(struct mii_dev *bus, int phy0)
> +{
> +       u16 reg, crc;
> +       int ret;
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_STD);
> +
> +       reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS);
> +       reg |= SMI_BROADCAST_WR_EN;
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS, reg);
> +
> +       reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_BYPASS_CONTROL);
> +       reg |= PARALLEL_DET_IGNORE_ADVERTISED;
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_BYPASS_CONTROL, reg);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_EXT3);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_SERDES_TX_CRC_ERR_CNT,
> +                  0x2000);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_TEST);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_5, 0x1f20);
> +
> +       reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8);
> +       reg |= 0x8000;

Comment, use BIT(31), and use #define

> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8, reg);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_TR);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16, 0xafa4);
> +
> +       reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18);
> +       reg &= ~0x007f;

Use GENMASK() and #define

> +       reg |= 0x0019;

Magic number... use #define.

> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16, 0x8fa4);

Magic number... use #define

> +

Comment what this is doing and link the errata that it came from...

> +       vsc8584_csr_write(bus, phy0, 0x07fa, 0x0050100f);
> +       vsc8584_csr_write(bus, phy0, 0x1688, 0x00049f81);
> +       vsc8584_csr_write(bus, phy0, 0x0f90, 0x00688980);
> +       vsc8584_csr_write(bus, phy0, 0x03a4, 0x0000d8f0);
> +       vsc8584_csr_write(bus, phy0, 0x0fc0, 0x00000400);
> +       vsc8584_csr_write(bus, phy0, 0x0f82, 0x0012b002);
> +       vsc8584_csr_write(bus, phy0, 0x1686, 0x00000004);
> +       vsc8584_csr_write(bus, phy0, 0x168c, 0x00d2c46f);
> +       vsc8584_csr_write(bus, phy0, 0x17a2, 0x00000620);
> +       vsc8584_csr_write(bus, phy0, 0x16a0, 0x00eeffdd);
> +       vsc8584_csr_write(bus, phy0, 0x16a6, 0x00071448);
> +       vsc8584_csr_write(bus, phy0, 0x16a4, 0x0013132f);
> +       vsc8584_csr_write(bus, phy0, 0x16a8, 0x00000000);
> +       vsc8584_csr_write(bus, phy0, 0x0ffc, 0x00c0a028);
> +       vsc8584_csr_write(bus, phy0, 0x0fe8, 0x0091b06c);
> +       vsc8584_csr_write(bus, phy0, 0x0fea, 0x00041600);
> +       vsc8584_csr_write(bus, phy0, 0x0f80, 0x00fffaff);
> +       vsc8584_csr_write(bus, phy0, 0x0fec, 0x00901809);
> +       vsc8584_csr_write(bus, phy0, 0x0ffe, 0x00b01007);
> +       vsc8584_csr_write(bus, phy0, 0x16b0, 0x00eeff00);
> +       vsc8584_csr_write(bus, phy0, 0x16b2, 0x00007000);
> +       vsc8584_csr_write(bus, phy0, 0x16b4, 0x00000814);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_EXT2);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_CU_PMD_TX_CNTL, 0x028e);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_TR);
> +
> +       vsc8584_csr_write(bus, phy0, 0x0486, 0x0008a518);
> +       vsc8584_csr_write(bus, phy0, 0x0488, 0x006dc696);
> +       vsc8584_csr_write(bus, phy0, 0x048a, 0x00000912);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_TEST);
> +
> +       reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8);
> +       reg &= ~0x8000;
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_TEST_PAGE_8, reg);
> +
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_STD);
> +
> +       reg = bus->read(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS);
> +       reg &= ~SMI_BROADCAST_WR_EN;
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_PHY_EXT_CNTL_STATUS, reg);
> +
> +       ret = vsc8584_get_fw_crc(bus, phy0,
> +                                MSCC_VSC8584_REVB_INT8051_FW_START_ADDR, &crc,
> +                                fw_patch_vsc8584,
> +                                ARRAY_SIZE(fw_patch_vsc8584));
> +       if (ret)
> +               goto out;
> +
> +       if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC) {
> +               debug("FW CRC is not the expected one, patching FW...\n");
> +               if (vsc8584_patch_fw(bus, phy0, fw_patch_vsc8584,
> +                                    ARRAY_SIZE(fw_patch_vsc8584)))
> +                       pr_warn("failed to patch FW, expect non-optimal device\n");
> +       }
> +
> +       vsc8584_micro_deassert_reset(bus, phy0, false);
> +
> +       ret = vsc8584_get_fw_crc(bus, phy0,
> +                                MSCC_VSC8584_REVB_INT8051_FW_START_ADDR, &crc,
> +                                fw_patch_vsc8584,
> +                                ARRAY_SIZE(fw_patch_vsc8584));
> +       if (ret)
> +               goto out;
> +
> +       if (crc != MSCC_VSC8584_REVB_INT8051_FW_CRC)
> +               pr_warn("FW CRC after patching is not the expected one, expect non-optimal device\n");
> +
> +       ret = vsc8584_micro_assert_reset(bus, phy0);
> +       if (ret)
> +               goto out;
> +
> +       vsc8584_micro_deassert_reset(bus, phy0, true);
> +
> +out:
> +       bus->write(bus, phy0, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                  MSCC_PHY_PAGE_STD);
> +
> +       return ret;
> +}
>
>  static int mscc_vsc8531_vsc8541_init_scripts(struct phy_device *phydev)
>  {
> @@ -457,6 +898,96 @@ static int vsc8541_config(struct phy_device *phydev)
>         return genphy_config_aneg(phydev);
>  }
>
> +static int vsc8584_config(struct phy_device *phydev)
> +{
> +       int ret;
> +       u16 addr;
> +       u16 reg_val;
> +       u16 val;
> +       u16 base_addr;
> +
> +       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                 MSCC_PHY_PAGE_EXT1);
> +       addr = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_4);
> +       addr >>= PHY_CNTL_4_ADDR_POS;
> +
> +       val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_ACTIPHY_CNTL);
> +       if (val & PHY_ADDR_REVERSED)
> +               base_addr = phydev->addr + addr;
> +       else
> +               base_addr = phydev->addr - addr;
> +
> +       if ((phydev->phy_id & MSCC_DEV_REV_MASK) != VSC8584_REVB) {
> +               pr_warn("VSC8584 revA not officially supported, skipping firmware patching. Use at your own risk.\n");
> +       } else {
> +               ret = vsc8584_config_pre_init(phydev->bus, base_addr);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                 MSCC_PHY_PAGE_GPIO);
> +
> +       if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
> +               val = MAC_CFG_QSGMII;
> +       else
> +               val = MAC_CFG_SGMII;
> +
> +       reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_MAC_CFG_FASTLINK);
> +       reg_val &= ~MAC_CFG_MASK;
> +       reg_val |= val;
> +       ret = phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_MAC_CFG_FASTLINK,
> +                       reg_val);
> +       if (ret)
> +               return ret;
> +
> +       reg_val = PROC_CMD_MCB_ACCESS_MAC_CONF | PROC_CMD_RST_CONF_PORT |
> +               PROC_CMD_READ_MOD_WRITE_PORT;
> +       if (phydev->interface == PHY_INTERFACE_MODE_QSGMII)
> +               reg_val |= PROC_CMD_QSGMII_MAC;
> +       else
> +               reg_val |= PROC_CMD_SGMII_MAC;
> +
> +       ret = vsc8584_cmd(phydev->bus, phydev->addr, reg_val);
> +       if (ret)
> +               return ret;
> +
> +       mdelay(10);
> +
> +       /* Disable SerDes for 100Base-FX */
> +       ret = vsc8584_cmd(phydev->bus, phydev->addr, PROC_CMD_FIBER_MEDIA_CONF |
> +                         PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
> +                         PROC_CMD_READ_MOD_WRITE_PORT |
> +                         PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_100BASE_FX);
> +       if (ret)
> +               return ret;
> +
> +       /* Disable SerDes for 1000Base-X */
> +       ret = vsc8584_cmd(phydev->bus, phydev->addr, PROC_CMD_FIBER_MEDIA_CONF |
> +                         PROC_CMD_FIBER_PORT(addr) | PROC_CMD_FIBER_DISABLE |
> +                         PROC_CMD_READ_MOD_WRITE_PORT |
> +                         PROC_CMD_RST_CONF_PORT | PROC_CMD_FIBER_1000BASE_X);
> +       if (ret)
> +               return ret;
> +
> +       phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
> +                 MSCC_PHY_PAGE_STD);
> +       reg_val = phy_read(phydev, MDIO_DEVAD_NONE,
> +                          MSCC_PHY_EXT_PHY_CNTL_1_REG);
> +       reg_val &= ~(MEDIA_OP_MODE_MASK | VSC8584_MAC_IF_SELECTION_MASK);
> +       reg_val |= MEDIA_OP_MODE_COPPER |
> +               (VSC8584_MAC_IF_SELECTION_SGMII <<
> +                VSC8584_MAC_IF_SELECTION_POS);
> +       ret = phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_EXT_PHY_CNTL_1_REG,
> +                       reg_val);
> +
> +       ret = mscc_phy_soft_reset(phydev);
> +       if (ret != 0)
> +               return ret;
> +
> +       return genphy_config(phydev);
> +}
> +
>  static struct phy_driver VSC8530_driver = {
>         .name = "Microsemi VSC8530",
>         .uid = PHY_ID_VSC8530,
> @@ -497,12 +1028,23 @@ static struct phy_driver VSC8541_driver = {
>         .shutdown = &genphy_shutdown,
>  };
>
> +static struct phy_driver VSC8584_driver = {
> +       .name = "Microsemi VSC8584",
> +       .uid = PHY_ID_VSC8584,
> +       .mask = 0x000ffff0,
> +       .features = PHY_GBIT_FEATURES,
> +       .config = &vsc8584_config,
> +       .startup = &mscc_startup,
> +       .shutdown = &genphy_shutdown,
> +};
> +
>  int phy_mscc_init(void)
>  {
>         phy_register(&VSC8530_driver);
>         phy_register(&VSC8531_driver);
>         phy_register(&VSC8540_driver);
>         phy_register(&VSC8541_driver);
> +       phy_register(&VSC8584_driver);
>
>         return 0;
>  }
> --
> 2.17.1
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot


More information about the U-Boot mailing list