mediatek: import Airoha EN8811H phy driver from SDK
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
parent
fb45af7245
commit
506006f2fe
141
target/linux/mediatek/files/drivers/net/phy/air_en8811h.h
Normal file
141
target/linux/mediatek/files/drivers/net/phy/air_en8811h.h
Normal file
@ -0,0 +1,141 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*************************************************
|
||||
* FILE NAME: air_en8811h.h
|
||||
* PURPOSE:
|
||||
* EN8811H PHY Driver for Linux
|
||||
* NOTES:
|
||||
*
|
||||
* Copyright (C) 2023 Airoha Technology Corp.
|
||||
*************************************************/
|
||||
#ifndef __EN8811H_H
|
||||
#define __EN8811H_H
|
||||
|
||||
#define EN8811H_PHY_ID1 0x03a2
|
||||
#define EN8811H_PHY_ID2 0xa411
|
||||
#define EN8811H_PHY_ID ((EN8811H_PHY_ID1 << 16) | EN8811H_PHY_ID2)
|
||||
#define EN8811H_PHY_READY 0x02
|
||||
#define MAX_RETRY 25
|
||||
|
||||
#define EN8811H_TX_POL_NORMAL 0x1
|
||||
#define EN8811H_TX_POL_REVERSE 0x0
|
||||
|
||||
#define EN8811H_RX_POL_NORMAL (0x0 << 1)
|
||||
#define EN8811H_RX_POL_REVERSE (0x1 << 1)
|
||||
|
||||
|
||||
/***************************************************************
|
||||
* The following led_cfg example is for reference only.
|
||||
* LED0 Link 2500/Blink 2500 TxRx (GPIO5) <-> BASE_T_LED0,
|
||||
* LED1 Link 1000/Blink 1000 TxRx (GPIO4) <-> BASE_T_LED1,
|
||||
* LED2 Link 100 /Blink 100 TxRx (GPIO3) <-> BASE_T_LED2,
|
||||
***************************************************************/
|
||||
/* User-defined.B */
|
||||
#define AIR_LED0_ON (LED_ON_EVT_LINK_2500M)
|
||||
#define AIR_LED0_BLK (LED_BLK_EVT_2500M_TX_ACT | LED_BLK_EVT_2500M_RX_ACT)
|
||||
#define AIR_LED1_ON (LED_ON_EVT_LINK_1000M)
|
||||
#define AIR_LED1_BLK (LED_BLK_EVT_1000M_TX_ACT | LED_BLK_EVT_1000M_RX_ACT)
|
||||
#define AIR_LED2_ON (LED_ON_EVT_LINK_100M)
|
||||
#define AIR_LED2_BLK (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT)
|
||||
/* User-defined.E */
|
||||
|
||||
/* CL45 MDIO control */
|
||||
#define MII_MMD_ACC_CTL_REG 0x0d
|
||||
#define MII_MMD_ADDR_DATA_REG 0x0e
|
||||
#define MMD_OP_MODE_DATA BIT(14)
|
||||
|
||||
#define EN8811H_DRIVER_VERSION "v1.2.2"
|
||||
|
||||
#define LED_ON_CTRL(i) (0x024 + ((i)*2))
|
||||
#define LED_ON_EN (1 << 15)
|
||||
#define LED_ON_POL (1 << 14)
|
||||
#define LED_ON_EVT_MASK (0x1ff)
|
||||
/* LED ON Event Option.B */
|
||||
#define LED_ON_EVT_LINK_2500M (1 << 8)
|
||||
#define LED_ON_EVT_FORCE (1 << 6)
|
||||
#define LED_ON_EVT_LINK_DOWN (1 << 3)
|
||||
#define LED_ON_EVT_LINK_100M (1 << 1)
|
||||
#define LED_ON_EVT_LINK_1000M (1 << 0)
|
||||
/* LED ON Event Option.E */
|
||||
|
||||
#define LED_BLK_CTRL(i) (0x025 + ((i)*2))
|
||||
#define LED_BLK_EVT_MASK (0xfff)
|
||||
/* LED Blinking Event Option.B*/
|
||||
#define LED_BLK_EVT_2500M_RX_ACT (1 << 11)
|
||||
#define LED_BLK_EVT_2500M_TX_ACT (1 << 10)
|
||||
#define LED_BLK_EVT_FORCE (1 << 9)
|
||||
#define LED_BLK_EVT_100M_RX_ACT (1 << 3)
|
||||
#define LED_BLK_EVT_100M_TX_ACT (1 << 2)
|
||||
#define LED_BLK_EVT_1000M_RX_ACT (1 << 1)
|
||||
#define LED_BLK_EVT_1000M_TX_ACT (1 << 0)
|
||||
/* LED Blinking Event Option.E*/
|
||||
#define EN8811H_LED_COUNT 3
|
||||
|
||||
#define LED_BCR (0x021)
|
||||
#define LED_BCR_EXT_CTRL (1 << 15)
|
||||
#define LED_BCR_CLK_EN (1 << 3)
|
||||
#define LED_BCR_TIME_TEST (1 << 2)
|
||||
#define LED_BCR_MODE_MASK (3)
|
||||
#define LED_BCR_MODE_DISABLE (0)
|
||||
|
||||
#define LED_ON_DUR (0x022)
|
||||
#define LED_ON_DUR_MASK (0xffff)
|
||||
|
||||
#define LED_BLK_DUR (0x023)
|
||||
#define LED_BLK_DUR_MASK (0xffff)
|
||||
|
||||
#define UNIT_LED_BLINK_DURATION 1024
|
||||
|
||||
#define GET_BIT(val, bit) ((val & BIT(bit)) >> bit)
|
||||
|
||||
#define INVALID_DATA 0xffff
|
||||
#define PBUS_INVALID_DATA 0xffffffff
|
||||
|
||||
struct en8811h_priv {
|
||||
struct dentry *debugfs_root;
|
||||
unsigned int dm_crc32;
|
||||
unsigned int dsp_crc32;
|
||||
char buf[512];
|
||||
};
|
||||
|
||||
struct air_base_t_led_cfg {
|
||||
u16 en;
|
||||
u16 gpio;
|
||||
u16 pol;
|
||||
u16 on_cfg;
|
||||
u16 blk_cfg;
|
||||
};
|
||||
enum air_led_gpio {
|
||||
AIR_LED2_GPIO3 = 3,
|
||||
AIR_LED1_GPIO4,
|
||||
AIR_LED0_GPIO5,
|
||||
AIR_LED_LAST
|
||||
};
|
||||
|
||||
enum air_base_t_led {
|
||||
AIR_BASE_T_LED0,
|
||||
AIR_BASE_T_LED1,
|
||||
AIR_BASE_T_LED2,
|
||||
AIR_BASE_T_LED3
|
||||
};
|
||||
|
||||
enum air_led_blk_dur {
|
||||
AIR_LED_BLK_DUR_32M,
|
||||
AIR_LED_BLK_DUR_64M,
|
||||
AIR_LED_BLK_DUR_128M,
|
||||
AIR_LED_BLK_DUR_256M,
|
||||
AIR_LED_BLK_DUR_512M,
|
||||
AIR_LED_BLK_DUR_1024M,
|
||||
AIR_LED_BLK_DUR_LAST
|
||||
};
|
||||
|
||||
enum air_led_polarity {
|
||||
AIR_ACTIVE_LOW,
|
||||
AIR_ACTIVE_HIGH,
|
||||
};
|
||||
enum air_led_mode {
|
||||
AIR_LED_MODE_DISABLE,
|
||||
AIR_LED_MODE_USER_DEFINE,
|
||||
AIR_LED_MODE_LAST
|
||||
};
|
||||
|
||||
#endif /* End of __EN8811H_H */
|
1227
target/linux/mediatek/files/drivers/net/phy/air_en8811h_api.c
Normal file
1227
target/linux/mediatek/files/drivers/net/phy/air_en8811h_api.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,87 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*************************************************
|
||||
* FILE NAME: air_en8811h_api.h
|
||||
* PURPOSE:
|
||||
* EN8811H PHY Driver for Linux
|
||||
* NOTES:
|
||||
*
|
||||
* Copyright (C) 2023 Airoha Technology Corp.
|
||||
*************************************************/
|
||||
#ifndef __EN8811H_API_H
|
||||
#define __EN8811H_API_H
|
||||
#include <linux/version.h>
|
||||
|
||||
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
|
||||
#define phydev_mdio_bus(_dev) (_dev->bus)
|
||||
#define phydev_addr(_dev) (_dev->addr)
|
||||
#define phydev_dev(_dev) (&_dev->dev)
|
||||
#else
|
||||
#define phydev_mdio_bus(_dev) (_dev->mdio.bus)
|
||||
#define phydev_addr(_dev) (_dev->mdio.addr)
|
||||
#define phydev_dev(_dev) (&_dev->mdio.dev)
|
||||
#endif
|
||||
|
||||
#define BUFFER_LENGTH 512
|
||||
|
||||
#define DEBUGFS_COUNTER "counter"
|
||||
#define DEBUGFS_DRIVER_INFO "drvinfo"
|
||||
#define DEBUGFS_PORT_MODE "port_mode"
|
||||
#define DEBUGFS_BUCKPBUS_OP "buckpbus_op"
|
||||
#define DEBUGFS_PBUS_OP "pbus_op"
|
||||
#define DEBUGFS_POLARITY "polarity"
|
||||
#define DEBUGFS_LINK_STATUS "link_status"
|
||||
#define DEBUGFS_DBG_REG_SHOW "dbg_regs_show"
|
||||
|
||||
enum air_port_mode {
|
||||
AIR_PORT_MODE_FORCE_100,
|
||||
AIR_PORT_MODE_FORCE_1000,
|
||||
AIR_PORT_MODE_FORCE_2500,
|
||||
AIR_PORT_MODE_AUTONEGO,
|
||||
AIR_PORT_MODE_POWER_DOWN,
|
||||
AIR_PORT_MODE_POWER_UP,
|
||||
AIR_PORT_MODE_FC_UNSUPPORT,
|
||||
AIR_PORT_MODE_FC_SUPPORT,
|
||||
AIR_PORT_MODE_FC_DIS,
|
||||
AIR_PORT_MODE_FC_EN,
|
||||
AIR_PORT_MODE_LAST = 0xFF,
|
||||
};
|
||||
|
||||
enum air_polarity {
|
||||
AIR_POL_TX_REV_RX_NOR,
|
||||
AIR_POL_TX_NOR_RX_NOR,
|
||||
AIR_POL_TX_REV_RX_REV,
|
||||
AIR_POL_TX_NOR_RX_REV,
|
||||
AIR_POL_TX_NOR_RX_LAST = 0xff,
|
||||
};
|
||||
|
||||
/* Link mode bit indices */
|
||||
enum air_link_mode_bit {
|
||||
AIR_LINK_MODE_10baseT_Half_BIT = 0,
|
||||
AIR_LINK_MODE_10baseT_Full_BIT = 1,
|
||||
AIR_LINK_MODE_100baseT_Half_BIT = 2,
|
||||
AIR_LINK_MODE_100baseT_Full_BIT = 3,
|
||||
AIR_LINK_MODE_1000baseT_Full_BIT = 4,
|
||||
AIR_LINK_MODE_2500baseT_Full_BIT = 5,
|
||||
};
|
||||
|
||||
#ifndef unlikely
|
||||
# define unlikely(x) (x)
|
||||
#endif
|
||||
int air_pbus_reg_write(struct phy_device *phydev,
|
||||
unsigned int pbus_address, unsigned int pbus_data);
|
||||
int air_mii_cl22_write(struct mii_bus *ebus, int addr,
|
||||
unsigned int phy_register, unsigned int write_data);
|
||||
int air_mii_cl22_read(struct mii_bus *ebus,
|
||||
int addr, unsigned int phy_register);
|
||||
int air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg);
|
||||
int air_mii_cl45_write(struct phy_device *phydev,
|
||||
int devad, u16 reg, u16 write_data);
|
||||
unsigned int air_buckpbus_reg_read(struct phy_device *phydev,
|
||||
unsigned int pbus_address);
|
||||
int air_buckpbus_reg_write(struct phy_device *phydev,
|
||||
unsigned int pbus_address, unsigned int pbus_data);
|
||||
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
|
||||
int airphy_debugfs_init(struct phy_device *phydev);
|
||||
void air_debugfs_remove(struct phy_device *phydev);
|
||||
#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
|
||||
#endif /* End of __EN8811H_API_H */
|
9227
target/linux/mediatek/files/drivers/net/phy/air_en8811h_fw.h
Normal file
9227
target/linux/mediatek/files/drivers/net/phy/air_en8811h_fw.h
Normal file
File diff suppressed because it is too large
Load Diff
454
target/linux/mediatek/files/drivers/net/phy/air_en8811h_main.c
Normal file
454
target/linux/mediatek/files/drivers/net/phy/air_en8811h_main.c
Normal file
@ -0,0 +1,454 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*************************************************
|
||||
* FILE NAME: air_en8811h_main.c
|
||||
* PURPOSE:
|
||||
* EN8811H PHY Driver for Linux
|
||||
* NOTES:
|
||||
*
|
||||
* Copyright (C) 2023 Airoha Technology Corp.
|
||||
*************************************************/
|
||||
|
||||
/* INCLUDE FILE DECLARATIONS
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/of.h>
|
||||
#include "air_en8811h_api.h"
|
||||
#include "air_en8811h_fw.h"
|
||||
#include "air_en8811h.h"
|
||||
|
||||
MODULE_DESCRIPTION("Airoha EN8811H PHY Drivers");
|
||||
MODULE_AUTHOR("Airoha");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/**************************
|
||||
* GPIO5 <-> BASE_T_LED0,
|
||||
* GPIO4 <-> BASE_T_LED1,
|
||||
* GPIO3 <-> BASE_T_LED2,
|
||||
**************************/
|
||||
/* User-defined.B */
|
||||
#define AIR_LED_SUPPORT
|
||||
#ifdef AIR_LED_SUPPORT
|
||||
static const struct air_base_t_led_cfg led_cfg[3] = {
|
||||
/********************************************************************
|
||||
*Enable, GPIO, LED Polarity, LED ON, LED Blink
|
||||
*********************************************************************/
|
||||
{1, AIR_LED0_GPIO5, AIR_ACTIVE_HIGH, AIR_LED0_ON, AIR_LED0_BLK},
|
||||
{1, AIR_LED1_GPIO4, AIR_ACTIVE_HIGH, AIR_LED1_ON, AIR_LED1_BLK},
|
||||
{1, AIR_LED2_GPIO3, AIR_ACTIVE_HIGH, AIR_LED2_ON, AIR_LED2_BLK},
|
||||
};
|
||||
static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
|
||||
#endif
|
||||
/* User-defined.E */
|
||||
|
||||
/***********************************************************
|
||||
* F U N C T I O N S
|
||||
***********************************************************/
|
||||
|
||||
|
||||
static int MDIOWriteBuf(struct phy_device *phydev, unsigned long address,
|
||||
unsigned long array_size, const unsigned char *buffer)
|
||||
{
|
||||
unsigned int write_data, offset;
|
||||
int ret = 0;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
struct mii_bus *mbus = phydev_mdio_bus(phydev);
|
||||
int addr = phydev_addr(phydev);
|
||||
/* page 4 */
|
||||
ret = air_mii_cl22_write(mbus, addr, 0x1F, 4);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
/* address increment*/
|
||||
ret = air_mii_cl22_write(mbus, addr, 0x10, 0x8000);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = air_mii_cl22_write(mbus, addr, 0x11,
|
||||
(u32)((address >> 16) & 0xffff));
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = air_mii_cl22_write(mbus, addr, 0x12, (u32)(address & 0xffff));
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (offset = 0; offset < array_size; offset += 4) {
|
||||
write_data = (buffer[offset + 3] << 8) | buffer[offset + 2];
|
||||
ret = air_mii_cl22_write(mbus, addr, 0x13, write_data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
write_data = (buffer[offset + 1] << 8) | buffer[offset];
|
||||
ret = air_mii_cl22_write(mbus, addr, 0x14, write_data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = air_mii_cl22_write(mbus, addr, 0x1F, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "air_mii_cl22_write, ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en8811h_load_firmware(struct phy_device *phydev)
|
||||
{
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
int ret = 0;
|
||||
u32 pbus_value = 0;
|
||||
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
#endif
|
||||
ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
|
||||
pbus_value |= BIT(11);
|
||||
ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Download DM */
|
||||
ret = MDIOWriteBuf(phydev, 0x00000000, EthMD32_dm_size, EthMD32_dm);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"MDIOWriteBuf 0x00000000 fail, ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
/* Download PM */
|
||||
ret = MDIOWriteBuf(phydev, 0x00100000, EthMD32_pm_size, EthMD32_pm);
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"MDIOWriteBuf 0x00100000 fail , ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
|
||||
pbus_value &= ~BIT(11);
|
||||
ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x01);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef AIR_LED_SUPPORT
|
||||
static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity,
|
||||
int polar, u16 on_evt, u16 blk_evt)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (polar == AIR_ACTIVE_HIGH)
|
||||
on_evt |= LED_ON_POL;
|
||||
else
|
||||
on_evt &= ~LED_ON_POL;
|
||||
|
||||
ret = air_mii_cl45_write(phydev, 0x1f,
|
||||
LED_ON_CTRL(entity), on_evt | LED_ON_EN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int airoha_led_set_mode(struct phy_device *phydev, u8 mode)
|
||||
{
|
||||
u16 cl45_data;
|
||||
int err = 0;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
|
||||
cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_BCR);
|
||||
switch (mode) {
|
||||
case AIR_LED_MODE_DISABLE:
|
||||
cl45_data &= ~LED_BCR_EXT_CTRL;
|
||||
cl45_data &= ~LED_BCR_MODE_MASK;
|
||||
cl45_data |= LED_BCR_MODE_DISABLE;
|
||||
break;
|
||||
case AIR_LED_MODE_USER_DEFINE:
|
||||
cl45_data |= LED_BCR_EXT_CTRL;
|
||||
cl45_data |= LED_BCR_CLK_EN;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "LED mode%d is not supported!\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
err = air_mii_cl45_write(phydev, 0x1f, LED_BCR, cl45_data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state)
|
||||
{
|
||||
u16 cl45_data = 0;
|
||||
int err;
|
||||
|
||||
cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity));
|
||||
if (state == 1)
|
||||
cl45_data |= LED_ON_EN;
|
||||
else
|
||||
cl45_data &= ~LED_ON_EN;
|
||||
|
||||
err = air_mii_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), cl45_data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en8811h_led_init(struct phy_device *phydev)
|
||||
{
|
||||
|
||||
unsigned long led_gpio = 0, reg_value = 0;
|
||||
u16 cl45_data = led_dur;
|
||||
int ret = 0, id;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
|
||||
ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_DUR, cl45_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cl45_data >>= 1;
|
||||
ret = air_mii_cl45_write(phydev, 0x1f, LED_ON_DUR, cl45_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "led_set_mode fail(ret:%d)!\n", ret);
|
||||
return ret;
|
||||
}
|
||||
for (id = 0; id < EN8811H_LED_COUNT; id++) {
|
||||
/* LED0 <-> GPIO5, LED1 <-> GPIO4, LED0 <-> GPIO3 */
|
||||
if (led_cfg[id].gpio != (id + (AIR_LED0_GPIO5 - (2 * id)))) {
|
||||
dev_err(dev, "LED%d uses incorrect GPIO%d !\n",
|
||||
id, led_cfg[id].gpio);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = airoha_led_set_state(phydev, id, led_cfg[id].en);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "led_set_state fail(ret:%d)!\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (led_cfg[id].en == 1) {
|
||||
led_gpio |= BIT(led_cfg[id].gpio);
|
||||
ret = airoha_led_set_usr_def(phydev, id,
|
||||
led_cfg[id].pol, led_cfg[id].on_cfg,
|
||||
led_cfg[id].blk_cfg);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "led_set_usr_def fail!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
reg_value = air_buckpbus_reg_read(phydev, 0xcf8b8) | led_gpio;
|
||||
ret = air_buckpbus_reg_write(phydev, 0xcf8b8, reg_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
dev_info(dev, "LED initialize OK !\n");
|
||||
return 0;
|
||||
}
|
||||
#endif /* AIR_LED_SUPPORT */
|
||||
#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
|
||||
static int en8811h_get_features(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
|
||||
dev_dbg(dev, "%s()\n", __func__);
|
||||
ret = air_pbus_reg_write(phydev, 0xcf928, 0x0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = genphy_read_abilities(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* EN8811H supports 100M/1G/2.5G speed. */
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
|
||||
phydev->supported);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
phydev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
|
||||
phydev->supported);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int en8811h_probe(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0;
|
||||
int reg_value, pid1 = 0, pid2 = 0;
|
||||
u32 retry, pbus_value = 0;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
struct mii_bus *mbus = phydev_mdio_bus(phydev);
|
||||
int addr = phydev_addr(phydev);
|
||||
|
||||
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
|
||||
struct en8811h_priv *priv;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
phydev->priv = priv;
|
||||
#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
|
||||
ret = air_pbus_reg_write(phydev, 0xcf928, 0x0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pid1 = air_mii_cl22_read(mbus, addr, MII_PHYSID1);
|
||||
if (pid1 < 0)
|
||||
return pid1;
|
||||
pid2 = air_mii_cl22_read(mbus, addr, MII_PHYSID2);
|
||||
if (pid2 < 0)
|
||||
return pid2;
|
||||
dev_info(dev, "PHY = %x - %x\n", pid1, pid2);
|
||||
if ((pid1 != EN8811H_PHY_ID1) || (pid2 != EN8811H_PHY_ID2)) {
|
||||
dev_err(dev, "EN8811H does not exist !\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0xcf914);
|
||||
dev_info(dev, "Bootmode: %s\n",
|
||||
(GET_BIT(pbus_value, 24) ? "Flash" : "Download Code"));
|
||||
|
||||
ret = en8811h_load_firmware(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "EN8811H load firmware fail.\n");
|
||||
return ret;
|
||||
}
|
||||
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
|
||||
ret = airphy_debugfs_init(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "air_debug_procfs_init fail. (ret=%d)\n", ret);
|
||||
air_debugfs_remove(phydev);
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_AIROHA_EN8811H_PHY_DEBUGFS */
|
||||
retry = MAX_RETRY;
|
||||
do {
|
||||
mdelay(300);
|
||||
reg_value = air_mii_cl45_read(phydev, 0x1e, 0x8009);
|
||||
if (reg_value == EN8811H_PHY_READY) {
|
||||
dev_info(dev, "EN8811H PHY ready!\n");
|
||||
break;
|
||||
}
|
||||
retry--;
|
||||
} while (retry);
|
||||
if (retry == 0) {
|
||||
dev_err(dev, "MD32 FW is not ready.(Status 0x%x)\n", reg_value);
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
|
||||
dev_err(dev,
|
||||
"Check MD32 FW Version(0x3b3c) : %08x\n", pbus_value);
|
||||
dev_err(dev,
|
||||
"EN8811H initialize fail!\n");
|
||||
return 0;
|
||||
}
|
||||
/* Mode selection*/
|
||||
dev_info(dev, "EN8811H Mode 1 !\n");
|
||||
ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Serdes polarity */
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
|
||||
pbus_value &= ~0x3;
|
||||
pbus_value |= ((device_property_read_bool(dev, "airoha,rx-pol-reverse") ?
|
||||
EN8811H_RX_POL_REVERSE : EN8811H_RX_POL_NORMAL) |
|
||||
(device_property_read_bool(dev, "airoha,tx-pol-reverse") ?
|
||||
EN8811H_TX_POL_REVERSE : EN8811H_TX_POL_NORMAL));
|
||||
ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
|
||||
dev_info(dev, "Tx, Rx Polarity : %08x\n", pbus_value);
|
||||
pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
|
||||
dev_info(dev, "MD32 FW Version : %08x\n", pbus_value);
|
||||
#if defined(AIR_LED_SUPPORT)
|
||||
ret = en8811h_led_init(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
dev_info(dev, "EN8811H initialize OK! (%s)\n", EN8811H_DRIVER_VERSION);
|
||||
return 0;
|
||||
}
|
||||
void en8811h_remove(struct phy_device *phydev)
|
||||
{
|
||||
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
struct device *dev = phydev_dev(phydev);
|
||||
|
||||
dev_dbg(dev, "%s: start\n", __func__);
|
||||
if (priv) {
|
||||
dev_info(dev, "%s: air_debugfs_remove\n", __func__);
|
||||
air_debugfs_remove(phydev);
|
||||
kfree(priv);
|
||||
}
|
||||
#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/
|
||||
}
|
||||
|
||||
static struct phy_driver en8811h_driver[] = {
|
||||
{
|
||||
.phy_id = EN8811H_PHY_ID,
|
||||
.name = "Airoha EN8811H",
|
||||
.phy_id_mask = 0x0ffffff0,
|
||||
.probe = en8811h_probe,
|
||||
.remove = en8811h_remove,
|
||||
#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
|
||||
.get_features = en8811h_get_features,
|
||||
.read_mmd = air_mii_cl45_read,
|
||||
.write_mmd = air_mii_cl45_write,
|
||||
#endif
|
||||
} };
|
||||
|
||||
int __init en8811h_phy_driver_register(void)
|
||||
{
|
||||
int ret;
|
||||
#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE)
|
||||
ret = phy_driver_register(en8811h_driver);
|
||||
#else
|
||||
ret = phy_driver_register(en8811h_driver, THIS_MODULE);
|
||||
#endif
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
phy_driver_unregister(en8811h_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __exit en8811h_phy_driver_unregister(void)
|
||||
{
|
||||
phy_driver_unregister(en8811h_driver);
|
||||
}
|
||||
|
||||
module_init(en8811h_phy_driver_register);
|
||||
module_exit(en8811h_phy_driver_unregister);
|
@ -1,5 +1,7 @@
|
||||
CONFIG_64BIT=y
|
||||
# CONFIG_AHCI_MTK is not set
|
||||
CONFIG_AIROHA_EN8811H_PHY=y
|
||||
# CONFIG_AIROHA_EN8811H_PHY_DEBUGFS is not set
|
||||
CONFIG_AQUANTIA_PHY=y
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=y
|
||||
|
@ -1,5 +1,7 @@
|
||||
CONFIG_64BIT=y
|
||||
# CONFIG_AHCI_MTK is not set
|
||||
CONFIG_AIROHA_EN8811H_PHY=y
|
||||
# CONFIG_AIROHA_EN8811H_PHY_DEBUGFS is not set
|
||||
CONFIG_AQUANTIA_PHY=y
|
||||
CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y
|
||||
CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
|
||||
|
@ -1,5 +1,6 @@
|
||||
CONFIG_64BIT=y
|
||||
# CONFIG_AHCI_MTK is not set
|
||||
# CONFIG_AIROHA_EN8811H_PHY is not set
|
||||
CONFIG_AQUANTIA_PHY=y
|
||||
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
|
||||
CONFIG_ARCH_KEEP_MEMBLOCK=y
|
||||
|
@ -1,5 +1,6 @@
|
||||
CONFIG_64BIT=y
|
||||
# CONFIG_AHCI_MTK is not set
|
||||
# CONFIG_AIROHA_EN8811H_PHY is not set
|
||||
CONFIG_AQUANTIA_PHY=y
|
||||
CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS=y
|
||||
CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
|
||||
|
@ -1,4 +1,5 @@
|
||||
# CONFIG_AIO is not set
|
||||
# CONFIG_AIROHA_EN8811H_PHY is not set
|
||||
CONFIG_ALIGNMENT_TRAP=y
|
||||
CONFIG_ARCH_32BIT_OFF_T=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
|
@ -1,4 +1,5 @@
|
||||
# CONFIG_AIO is not set
|
||||
# CONFIG_AIROHA_EN8811H_PHY is not set
|
||||
CONFIG_ALIGNMENT_TRAP=y
|
||||
CONFIG_ARCH_32BIT_OFF_T=y
|
||||
CONFIG_ARCH_FORCE_MAX_ORDER=11
|
||||
|
@ -1,3 +1,4 @@
|
||||
# CONFIG_AIROHA_EN8811H_PHY is not set
|
||||
CONFIG_ALIGNMENT_TRAP=y
|
||||
CONFIG_ARCH_32BIT_OFF_T=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
|
@ -1,3 +1,4 @@
|
||||
# CONFIG_AIROHA_EN8811H_PHY is not set
|
||||
CONFIG_ALIGNMENT_TRAP=y
|
||||
CONFIG_ARCH_32BIT_OFF_T=y
|
||||
CONFIG_ARCH_FORCE_MAX_ORDER=11
|
||||
|
@ -0,0 +1,48 @@
|
||||
From 4a6ecbd197764499d808309f372341370a89f88c Mon Sep 17 00:00:00 2001
|
||||
From: Sam Shih <sam.shih@mediatek.com>
|
||||
Date: Sun, 11 Jun 2023 01:59:14 +0100
|
||||
Subject: [PATCH] net: phy: add driver for Airoha EN8811 2.5G PHY
|
||||
|
||||
2500Base-T PHY with ID 0x03a2a411, needs firmware upload
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/phy/Kconfig | 5 +
|
||||
drivers/net/phy/Makefile | 1 +
|
||||
drivers/net/phy/air_en8811h.c | 708 ++++++++++++++++++++++++++++++++++
|
||||
drivers/net/phy/air_en8811h.h | 151 ++++++++
|
||||
4 files changed, 865 insertions(+)
|
||||
create mode 100644 drivers/net/phy/air_en8811h.c
|
||||
create mode 100644 drivers/net/phy/air_en8811h.h
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -149,6 +149,17 @@ config MESON_GXL_PHY
|
||||
help
|
||||
Currently has a driver for the Amlogic Meson GXL Internal PHY
|
||||
|
||||
+config AIROHA_EN8811H_PHY
|
||||
+ tristate "Airoha EN8811H 2.5G Gigabit PHY"
|
||||
+ help
|
||||
+ Currently supports the Airoha EN8811H PHY.
|
||||
+
|
||||
+config AIROHA_EN8811H_PHY_DEBUGFS
|
||||
+ bool "EN8811H debugfs support"
|
||||
+ depends on AIROHA_EN8811H_PHY
|
||||
+ help
|
||||
+ Enable creation of debugfs files for the EN8811H drivers.
|
||||
+
|
||||
config ADIN_PHY
|
||||
tristate "Analog Devices Industrial Ethernet PHYs"
|
||||
help
|
||||
--- a/drivers/net/phy/Makefile
|
||||
+++ b/drivers/net/phy/Makefile
|
||||
@@ -51,6 +51,8 @@ aquantia-objs += aquantia_main.o
|
||||
ifdef CONFIG_HWMON
|
||||
aquantia-objs += aquantia_hwmon.o
|
||||
endif
|
||||
+air_en8811h-y := air_en8811h_main.o air_en8811h_api.o
|
||||
+obj-$(CONFIG_AIROHA_EN8811H_PHY) += air_en8811h.o
|
||||
obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
|
||||
obj-$(CONFIG_AT803X_PHY) += at803x.o
|
||||
obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
|
@ -66,4 +66,4 @@ Signed-off-by: Yangyu Chen <cyy@cyyself.name>
|
||||
+ return rtl8221b_config_led(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver realtek_drvs[] = {
|
||||
static int rtl8221b_ack_interrupt(struct phy_device *phydev)
|
||||
|
@ -0,0 +1,48 @@
|
||||
From 4a6ecbd197764499d808309f372341370a89f88c Mon Sep 17 00:00:00 2001
|
||||
From: Sam Shih <sam.shih@mediatek.com>
|
||||
Date: Sun, 11 Jun 2023 01:59:14 +0100
|
||||
Subject: [PATCH] net: phy: add driver for Airoha EN8811 2.5G PHY
|
||||
|
||||
2500Base-T PHY with ID 0x03a2a411, needs firmware upload
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/phy/Kconfig | 5 +
|
||||
drivers/net/phy/Makefile | 1 +
|
||||
drivers/net/phy/air_en8811h.c | 708 ++++++++++++++++++++++++++++++++++
|
||||
drivers/net/phy/air_en8811h.h | 151 ++++++++
|
||||
4 files changed, 865 insertions(+)
|
||||
create mode 100644 drivers/net/phy/air_en8811h.c
|
||||
create mode 100644 drivers/net/phy/air_en8811h.h
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -156,6 +156,17 @@ config MESON_GXL_PHY
|
||||
help
|
||||
Currently has a driver for the Amlogic Meson GXL Internal PHY
|
||||
|
||||
+config AIROHA_EN8811H_PHY
|
||||
+ tristate "Airoha EN8811H 2.5G Gigabit PHY"
|
||||
+ help
|
||||
+ Currently supports the Airoha EN8811H PHY.
|
||||
+
|
||||
+config AIROHA_EN8811H_PHY_DEBUGFS
|
||||
+ bool "EN8811H debugfs support"
|
||||
+ depends on AIROHA_EN8811H_PHY
|
||||
+ help
|
||||
+ Enable creation of debugfs files for the EN8811H drivers.
|
||||
+
|
||||
config ADIN_PHY
|
||||
tristate "Analog Devices Industrial Ethernet PHYs"
|
||||
help
|
||||
--- a/drivers/net/phy/Makefile
|
||||
+++ b/drivers/net/phy/Makefile
|
||||
@@ -52,6 +52,8 @@ aquantia-objs += aquantia_main.o
|
||||
ifdef CONFIG_HWMON
|
||||
aquantia-objs += aquantia_hwmon.o
|
||||
endif
|
||||
+air_en8811h-y := air_en8811h_main.o air_en8811h_api.o
|
||||
+obj-$(CONFIG_AIROHA_EN8811H_PHY) += air_en8811h.o
|
||||
obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
|
||||
obj-$(CONFIG_AT803X_PHY) += at803x.o
|
||||
obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
|
@ -66,4 +66,4 @@ Signed-off-by: Yangyu Chen <cyy@cyyself.name>
|
||||
+ return rtl8221b_config_led(phydev);
|
||||
}
|
||||
|
||||
static struct phy_driver realtek_drvs[] = {
|
||||
static int rtl8221b_ack_interrupt(struct phy_device *phydev)
|
||||
|
Loading…
x
Reference in New Issue
Block a user