linux/drivers/net/phy/air_en8811h.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * Driver for the Airoha EN8811H 2.5 Gigabit PHY.
 *
 * Limitations of the EN8811H:
 * - Only full duplex supported
 * - Forced speed (AN off) is not supported by hardware (100Mbps)
 *
 * Source originated from airoha's en8811h.c and en8811h.h v1.2.1
 *
 * Copyright (C) 2023 Airoha Technology Corp.
 */

#include <linux/phy.h>
#include <linux/firmware.h>
#include <linux/property.h>
#include <linux/wordpart.h>
#include <asm/unaligned.h>

#define EN8811H_PHY_ID

#define EN8811H_MD32_DM
#define EN8811H_MD32_DSP

#define AIR_FW_ADDR_DM
#define AIR_FW_ADDR_DSP

/* MII Registers */
#define AIR_AUX_CTRL_STATUS
#define AIR_AUX_CTRL_STATUS_SPEED_MASK
#define AIR_AUX_CTRL_STATUS_SPEED_100
#define AIR_AUX_CTRL_STATUS_SPEED_1000
#define AIR_AUX_CTRL_STATUS_SPEED_2500

#define AIR_EXT_PAGE_ACCESS
#define AIR_PHY_PAGE_STANDARD
#define AIR_PHY_PAGE_EXTENDED_4

/* MII Registers Page 4*/
#define AIR_BPBUS_MODE
#define AIR_BPBUS_MODE_ADDR_FIXED
#define AIR_BPBUS_MODE_ADDR_INCR
#define AIR_BPBUS_WR_ADDR_HIGH
#define AIR_BPBUS_WR_ADDR_LOW
#define AIR_BPBUS_WR_DATA_HIGH
#define AIR_BPBUS_WR_DATA_LOW
#define AIR_BPBUS_RD_ADDR_HIGH
#define AIR_BPBUS_RD_ADDR_LOW
#define AIR_BPBUS_RD_DATA_HIGH
#define AIR_BPBUS_RD_DATA_LOW

/* Registers on MDIO_MMD_VEND1 */
#define EN8811H_PHY_FW_STATUS
#define EN8811H_PHY_READY

#define AIR_PHY_MCU_CMD_1
#define AIR_PHY_MCU_CMD_1_MODE1
#define AIR_PHY_MCU_CMD_2
#define AIR_PHY_MCU_CMD_2_MODE1
#define AIR_PHY_MCU_CMD_3
#define AIR_PHY_MCU_CMD_3_MODE1
#define AIR_PHY_MCU_CMD_3_DOCMD
#define AIR_PHY_MCU_CMD_4
#define AIR_PHY_MCU_CMD_4_MODE1
#define AIR_PHY_MCU_CMD_4_INTCLR

/* Registers on MDIO_MMD_VEND2 */
#define AIR_PHY_LED_BCR
#define AIR_PHY_LED_BCR_MODE_MASK
#define AIR_PHY_LED_BCR_TIME_TEST
#define AIR_PHY_LED_BCR_CLK_EN
#define AIR_PHY_LED_BCR_EXT_CTRL

#define AIR_PHY_LED_DUR_ON

#define AIR_PHY_LED_DUR_BLINK

#define AIR_PHY_LED_ON(i)
#define AIR_PHY_LED_ON_MASK
#define AIR_PHY_LED_ON_LINK1000
#define AIR_PHY_LED_ON_LINK100
#define AIR_PHY_LED_ON_LINK10
#define AIR_PHY_LED_ON_LINKDOWN
#define AIR_PHY_LED_ON_FDX
#define AIR_PHY_LED_ON_HDX
#define AIR_PHY_LED_ON_FORCE_ON
#define AIR_PHY_LED_ON_LINK2500
#define AIR_PHY_LED_ON_POLARITY
#define AIR_PHY_LED_ON_ENABLE

#define AIR_PHY_LED_BLINK(i)
#define AIR_PHY_LED_BLINK_1000TX
#define AIR_PHY_LED_BLINK_1000RX
#define AIR_PHY_LED_BLINK_100TX
#define AIR_PHY_LED_BLINK_100RX
#define AIR_PHY_LED_BLINK_10TX
#define AIR_PHY_LED_BLINK_10RX
#define AIR_PHY_LED_BLINK_COLLISION
#define AIR_PHY_LED_BLINK_RX_CRC_ERR
#define AIR_PHY_LED_BLINK_RX_IDLE_ERR
#define AIR_PHY_LED_BLINK_FORCE_BLINK
#define AIR_PHY_LED_BLINK_2500TX
#define AIR_PHY_LED_BLINK_2500RX

/* Registers on BUCKPBUS */
#define EN8811H_2P5G_LPA
#define EN8811H_2P5G_LPA_2P5G

#define EN8811H_FW_VERSION

#define EN8811H_POLARITY
#define EN8811H_POLARITY_TX_NORMAL
#define EN8811H_POLARITY_RX_REVERSE

#define EN8811H_GPIO_OUTPUT
#define EN8811H_GPIO_OUTPUT_345

#define EN8811H_FW_CTRL_1
#define EN8811H_FW_CTRL_1_START
#define EN8811H_FW_CTRL_1_FINISH
#define EN8811H_FW_CTRL_2
#define EN8811H_FW_CTRL_2_LOADING

/* Led definitions */
#define EN8811H_LED_COUNT

/* Default LED setup:
 * GPIO5 <-> LED0  On: Link detected, blink Rx/Tx
 * GPIO4 <-> LED1  On: Link detected at 2500 or 1000 Mbps
 * GPIO3 <-> LED2  On: Link detected at 2500 or  100 Mbps
 */
#define AIR_DEFAULT_TRIGGER_LED0
#define AIR_DEFAULT_TRIGGER_LED1
#define AIR_DEFAULT_TRIGGER_LED2

struct led {};

struct en8811h_priv {};

enum {};

enum {};

enum {};

enum {};

enum {};

#define AIR_PHY_LED_DUR_UNIT
#define AIR_PHY_LED_DUR

static const unsigned long en8811h_led_trig =;

static int air_phy_read_page(struct phy_device *phydev)
{}

static int air_phy_write_page(struct phy_device *phydev, int page)
{}

static int __air_buckpbus_reg_write(struct phy_device *phydev,
				    u32 pbus_address, u32 pbus_data)
{}

static int air_buckpbus_reg_write(struct phy_device *phydev,
				  u32 pbus_address, u32 pbus_data)
{}

static int __air_buckpbus_reg_read(struct phy_device *phydev,
				   u32 pbus_address, u32 *pbus_data)
{}

static int air_buckpbus_reg_read(struct phy_device *phydev,
				 u32 pbus_address, u32 *pbus_data)
{}

static int __air_buckpbus_reg_modify(struct phy_device *phydev,
				     u32 pbus_address, u32 mask, u32 set)
{}

static int air_buckpbus_reg_modify(struct phy_device *phydev,
				   u32 pbus_address, u32 mask, u32 set)
{}

static int __air_write_buf(struct phy_device *phydev, u32 address,
			   const struct firmware *fw)
{}

static int air_write_buf(struct phy_device *phydev, u32 address,
			 const struct firmware *fw)
{}

static int en8811h_wait_mcu_ready(struct phy_device *phydev)
{}

static int en8811h_load_firmware(struct phy_device *phydev)
{}

static int en8811h_restart_mcu(struct phy_device *phydev)
{}

static int air_hw_led_on_set(struct phy_device *phydev, u8 index, bool on)
{}

static int air_hw_led_blink_set(struct phy_device *phydev, u8 index,
				bool blinking)
{}

static int air_led_blink_set(struct phy_device *phydev, u8 index,
			     unsigned long *delay_on,
			     unsigned long *delay_off)
{}

static int air_led_brightness_set(struct phy_device *phydev, u8 index,
				  enum led_brightness value)
{}

static int air_led_hw_control_get(struct phy_device *phydev, u8 index,
				  unsigned long *rules)
{
	struct en8811h_priv *priv = phydev->priv;

	if (index >= EN8811H_LED_COUNT)
		return -EINVAL;

	*rules = priv->led[index].rules;

	return 0;
};

static int air_led_hw_control_set(struct phy_device *phydev, u8 index,
				  unsigned long rules)
{
	struct en8811h_priv *priv = phydev->priv;
	u16 on = 0, blink = 0;
	int ret;

	if (index >= EN8811H_LED_COUNT)
		return -EINVAL;

	priv->led[index].rules = rules;

	if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
		on |= AIR_PHY_LED_ON_FDX;

	if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK)))
		on |= AIR_PHY_LED_ON_LINK10;

	if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
		on |= AIR_PHY_LED_ON_LINK100;

	if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
		on |= AIR_PHY_LED_ON_LINK1000;

	if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
		on |= AIR_PHY_LED_ON_LINK2500;

	if (rules & BIT(TRIGGER_NETDEV_RX)) {
		blink |= AIR_PHY_LED_BLINK_10RX   |
			 AIR_PHY_LED_BLINK_100RX  |
			 AIR_PHY_LED_BLINK_1000RX |
			 AIR_PHY_LED_BLINK_2500RX;
	}

	if (rules & BIT(TRIGGER_NETDEV_TX)) {
		blink |= AIR_PHY_LED_BLINK_10TX   |
			 AIR_PHY_LED_BLINK_100TX  |
			 AIR_PHY_LED_BLINK_1000TX |
			 AIR_PHY_LED_BLINK_2500TX;
	}

	if (blink || on) {
		/* switch hw-control on, so led-on and led-blink are off */
		clear_bit(AIR_PHY_LED_STATE_FORCE_ON,
			  &priv->led[index].state);
		clear_bit(AIR_PHY_LED_STATE_FORCE_BLINK,
			  &priv->led[index].state);
	} else {
		priv->led[index].rules = 0;
	}

	ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index),
			     AIR_PHY_LED_ON_MASK, on);

	if (ret < 0)
		return ret;

	return phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BLINK(index),
			     blink);
};

static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol)
{}

static int air_leds_init(struct phy_device *phydev, int num, int dur, int mode)
{}

static int en8811h_led_hw_is_supported(struct phy_device *phydev, u8 index,
				       unsigned long rules)
{
	if (index >= EN8811H_LED_COUNT)
		return -EINVAL;

	/* All combinations of the supported triggers are allowed */
	if (rules & ~en8811h_led_trig)
		return -EOPNOTSUPP;

	return 0;
};

static int en8811h_probe(struct phy_device *phydev)
{}

static int en8811h_config_init(struct phy_device *phydev)
{}

static int en8811h_get_features(struct phy_device *phydev)
{}

static int en8811h_get_rate_matching(struct phy_device *phydev,
				     phy_interface_t iface)
{}

static int en8811h_config_aneg(struct phy_device *phydev)
{}

static int en8811h_read_status(struct phy_device *phydev)
{}

static int en8811h_clear_intr(struct phy_device *phydev)
{}

static irqreturn_t en8811h_handle_interrupt(struct phy_device *phydev)
{}

static struct phy_driver en8811h_driver[] =;

module_phy_driver(en8811h_driver);

static struct mdio_device_id __maybe_unused en8811h_tbl[] =;

MODULE_DEVICE_TABLE(mdio, en8811h_tbl);
MODULE_FIRMWARE();
MODULE_FIRMWARE();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_LICENSE();