// SPDX-License-Identifier: GPL-2.0
/*
* Marvell 88Q2XXX automotive 100BASE-T1/1000BASE-T1 PHY driver
*
* Derived from Marvell Q222x API
*
* Copyright (C) 2024 Liebherr-Electronics and Drives GmbH
*/
#include <linux/ethtool_netlink.h>
#include <linux/hwmon.h>
#include <linux/marvell_phy.h>
#include <linux/of.h>
#include <linux/phy.h>
#define PHY_ID_88Q2220_REVB0 (MARVELL_PHY_ID_88Q2220 | 0x1)
#define PHY_ID_88Q2220_REVB1 (MARVELL_PHY_ID_88Q2220 | 0x2)
#define PHY_ID_88Q2220_REVB2 (MARVELL_PHY_ID_88Q2220 | 0x3)
#define MDIO_MMD_AN_MV_STAT 32769
#define MDIO_MMD_AN_MV_STAT_ANEG 0x0100
#define MDIO_MMD_AN_MV_STAT_LOCAL_RX 0x1000
#define MDIO_MMD_AN_MV_STAT_REMOTE_RX 0x2000
#define MDIO_MMD_AN_MV_STAT_LOCAL_MASTER 0x4000
#define MDIO_MMD_AN_MV_STAT_MS_CONF_FAULT 0x8000
#define MDIO_MMD_AN_MV_STAT2 32794
#define MDIO_MMD_AN_MV_STAT2_AN_RESOLVED 0x0800
#define MDIO_MMD_AN_MV_STAT2_100BT1 0x2000
#define MDIO_MMD_AN_MV_STAT2_1000BT1 0x4000
#define MDIO_MMD_PCS_MV_RESET_CTRL 32768
#define MDIO_MMD_PCS_MV_RESET_CTRL_TX_DISABLE 0x8
#define MDIO_MMD_PCS_MV_INT_EN 32784
#define MDIO_MMD_PCS_MV_INT_EN_LINK_UP 0x0040
#define MDIO_MMD_PCS_MV_INT_EN_LINK_DOWN 0x0080
#define MDIO_MMD_PCS_MV_INT_EN_100BT1 0x1000
#define MDIO_MMD_PCS_MV_GPIO_INT_STAT 32785
#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_UP 0x0040
#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_LINK_DOWN 0x0080
#define MDIO_MMD_PCS_MV_GPIO_INT_STAT_100BT1_GEN 0x1000
#define MDIO_MMD_PCS_MV_GPIO_INT_CTRL 32787
#define MDIO_MMD_PCS_MV_GPIO_INT_CTRL_TRI_DIS 0x0800
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL 32790
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_1_MASK GENMASK(7, 4)
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LED_0_MASK GENMASK(3, 0)
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK 0x0 /* Link established */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_RX_TX 0x1 /* Link established, blink for rx or tx activity */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_1000BT1 0x2 /* Blink 3x for 1000BT1 link established */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_RX_TX_ON 0x3 /* Receive or transmit activity */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_RX_TX 0x4 /* Blink on receive or transmit activity */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_TX 0x5 /* Transmit activity */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_COPPER 0x6 /* Copper Link established */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_LINK_1000BT1_ON 0x7 /* 1000BT1 link established */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_OFF 0x8 /* Force off */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_ON 0x9 /* Force on */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_HIGHZ 0xa /* Force Hi-Z */
#define MDIO_MMD_PCS_MV_LED_FUNC_CTRL_FORCE_BLINK 0xb /* Force blink */
#define MDIO_MMD_PCS_MV_TEMP_SENSOR1 32833
#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_RAW_INT 0x0001
#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT 0x0040
#define MDIO_MMD_PCS_MV_TEMP_SENSOR1_INT_EN 0x0080
#define MDIO_MMD_PCS_MV_TEMP_SENSOR2 32834
#define MDIO_MMD_PCS_MV_TEMP_SENSOR2_DIS_MASK 0xc000
#define MDIO_MMD_PCS_MV_TEMP_SENSOR3 32835
#define MDIO_MMD_PCS_MV_TEMP_SENSOR3_INT_THRESH_MASK 0xff00
#define MDIO_MMD_PCS_MV_TEMP_SENSOR3_MASK 0x00ff
#define MDIO_MMD_PCS_MV_100BT1_STAT1 33032
#define MDIO_MMD_PCS_MV_100BT1_STAT1_IDLE_ERROR 0x00ff
#define MDIO_MMD_PCS_MV_100BT1_STAT1_JABBER 0x0100
#define MDIO_MMD_PCS_MV_100BT1_STAT1_LINK 0x0200
#define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_RX 0x1000
#define MDIO_MMD_PCS_MV_100BT1_STAT1_REMOTE_RX 0x2000
#define MDIO_MMD_PCS_MV_100BT1_STAT1_LOCAL_MASTER 0x4000
#define MDIO_MMD_PCS_MV_100BT1_STAT2 33033
#define MDIO_MMD_PCS_MV_100BT1_STAT2_JABBER 0x0001
#define MDIO_MMD_PCS_MV_100BT1_STAT2_POL 0x0002
#define MDIO_MMD_PCS_MV_100BT1_STAT2_LINK 0x0004
#define MDIO_MMD_PCS_MV_100BT1_STAT2_ANGE 0x0008
#define MDIO_MMD_PCS_MV_100BT1_INT_EN 33042
#define MDIO_MMD_PCS_MV_100BT1_INT_EN_LINKEVENT 0x0400
#define MDIO_MMD_PCS_MV_COPPER_INT_STAT 33043
#define MDIO_MMD_PCS_MV_COPPER_INT_STAT_LINKEVENT 0x0400
#define MDIO_MMD_PCS_MV_RX_STAT 33328
#define MDIO_MMD_PCS_MV_TDR_RESET 65226
#define MDIO_MMD_PCS_MV_TDR_RESET_TDR_RST 0x1000
#define MDIO_MMD_PCS_MV_TDR_OFF_SHORT_CABLE 65241
#define MDIO_MMD_PCS_MV_TDR_OFF_LONG_CABLE 65242
#define MDIO_MMD_PCS_MV_TDR_STATUS 65245
#define MDIO_MMD_PCS_MV_TDR_STATUS_MASK 0x0003
#define MDIO_MMD_PCS_MV_TDR_STATUS_OFF 0x0001
#define MDIO_MMD_PCS_MV_TDR_STATUS_ON 0x0002
#define MDIO_MMD_PCS_MV_TDR_STATUS_DIST_MASK 0xff00
#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_MASK 0x00f0
#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_SHORT 0x0030
#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OPEN 0x00e0
#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_OK 0x0070
#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_IN_PROGR 0x0080
#define MDIO_MMD_PCS_MV_TDR_STATUS_VCT_STAT_NOISE 0x0050
#define MDIO_MMD_PCS_MV_TDR_OFF_CUTOFF 65246
#define MV88Q2XXX_LED_INDEX_TX_ENABLE 0
#define MV88Q2XXX_LED_INDEX_GPIO 1
struct mv88q2xxx_priv {
bool enable_led0;
};
struct mmd_val {
int devad;
u32 regnum;
u16 val;
};
static const struct mmd_val mv88q2110_init_seq0[] = {
{ MDIO_MMD_PCS, 0xffe4, 0x07b5 },
{ MDIO_MMD_PCS, 0xffe4, 0x06b6 },
};
static const struct mmd_val mv88q2110_init_seq1[] = {
{ MDIO_MMD_PCS, 0xffde, 0x402f },
{ MDIO_MMD_PCS, 0xfe34, 0x4040 },
{ MDIO_MMD_PCS, 0xfe2a, 0x3c1d },
{ MDIO_MMD_PCS, 0xfe34, 0x0040 },
{ MDIO_MMD_AN, 0x8032, 0x0064 },
{ MDIO_MMD_AN, 0x8031, 0x0a01 },
{ MDIO_MMD_AN, 0x8031, 0x0c01 },
{ MDIO_MMD_PCS, 0xffdb, 0x0010 },
};
static const struct mmd_val mv88q222x_revb0_init_seq0[] = {
{ MDIO_MMD_PCS, 0x8033, 0x6801 },
{ MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 },
{ MDIO_MMD_PMAPMD, MDIO_CTRL1,
MDIO_CTRL1_LPOWER | MDIO_PMA_CTRL1_SPEED1000 },
{ MDIO_MMD_PCS, 0xfe1b, 0x48 },
{ MDIO_MMD_PCS, 0xffe4, 0x6b6 },
{ MDIO_MMD_PMAPMD, MDIO_CTRL1, 0x0 },
{ MDIO_MMD_PCS, MDIO_CTRL1, 0x0 },
};
static const struct mmd_val mv88q222x_revb0_init_seq1[] = {
{ MDIO_MMD_PCS, 0xfe79, 0x0 },
{ MDIO_MMD_PCS, 0xfe07, 0x125a },
{ MDIO_MMD_PCS,