en8811h:use 1.2.5 version

This commit is contained in:
padavanonly 2025-04-08 22:21:27 +08:00
parent 5116de248b
commit 575201b5dc
9 changed files with 9611 additions and 4241 deletions

View File

@ -242,7 +242,6 @@
pinctrl-0 = <&en8811_pwr_a>;
airoha,polarity = <3>;
airoha,surge = <0>;
interrupt-parent = <&pio>;
interrupts = <48 IRQ_TYPE_LEVEL_HIGH>;
@ -262,7 +261,6 @@
pinctrl-0 = <&en8811_pwr_b>;
airoha,polarity = <3>;
airoha,surge = <0>;
interrupt-parent = <&pio>;
interrupts = <46 IRQ_TYPE_LEVEL_HIGH>;

View File

@ -147,31 +147,41 @@
#size-cells = <0>;
phy14: phy@14 {
/* EN8811H PHY ID */
compatible = "ethernet-phy-id03a2.a411";
/* PHY Address */
reg = <14>;
reset-gpios = <&pio 49 1>; /* GPIO49 */
pinctrl-names = "default";
pinctrl-0 = <&en8811_pwr_a>;
airoha,polarity = <3>;
interrupt-parent = <&pio>;
interrupts = <48 IRQ_TYPE_LEVEL_HIGH>;
reset-gpios = <&pio 49 1>;
reset-assert-us = <10000>;
reset-deassert-us = <20000>;
phy-mode = "2500base-x";
full-duplex;
pause;
airoha,polarity = <3>;
};
phy15: phy@15 {
/* EN8811H PHY ID */
compatible = "ethernet-phy-id03a2.a411";
/* PHY Address */
reg = <15>;
reset-gpios = <&pio 47 1>; /* GPIO47 */
pinctrl-names = "default";
pinctrl-0 = <&en8811_pwr_b>;
airoha,polarity = <3>;
interrupt-parent = <&pio>;
interrupts = <46 IRQ_TYPE_LEVEL_HIGH>;
reset-gpios = <&pio 47 1>;
reset-assert-us = <10000>;
reset-deassert-us = <20000>;
phy-mode = "2500base-x";
full-duplex;
pause;
airoha,polarity = <3>;
};
};
};

View File

@ -186,30 +186,40 @@
#size-cells = <0>;
phy14: phy@14 {
/* EN8811H PHY ID */
compatible = "ethernet-phy-id03a2.a411";
/* PHY Address */
reg = <14>;
reset-gpios = <&pio 49 1>; /* GPIO49 */
pinctrl-names = "default";
pinctrl-0 = <&en8811_pwr_a>;
airoha,polarity = <3>;
interrupt-parent = <&pio>;
interrupts = <48 IRQ_TYPE_LEVEL_HIGH>;
reset-gpios = <&pio 49 1>;
reset-assert-us = <10000>;
reset-deassert-us = <20000>;
phy-mode = "2500base-x";
full-duplex;
airoha,polarity = <3>;
pause;
};
phy15: phy@15 {
/* EN8811H PHY ID */
compatible = "ethernet-phy-id03a2.a411";
/* PHY Address */
reg = <15>;
reset-gpios = <&pio 47 1>; /* GPIO47 */
pinctrl-names = "default";
pinctrl-0 = <&en8811_pwr_b>;
airoha,polarity = <3>;
interrupt-parent = <&pio>;
interrupts = <46 IRQ_TYPE_LEVEL_HIGH>;
reset-gpios = <&pio 47 1>;
reset-assert-us = <10000>;
reset-deassert-us = <20000>;
phy-mode = "2500base-x";
full-duplex;
airoha,polarity = <3>;
pause;
};
};

View File

@ -10,15 +10,10 @@
#ifndef __EN8811H_H
#define __EN8811H_H
#define EN8811H_MD32_DM "EthMD32.dm.bin"
#define EN8811H_MD32_DSP "EthMD32.DSP.bin"
#define EN8811H_IVY "ivypram.bin"
#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 EN8811H_PHY_IVY_READY 0xABC
#define MAX_RETRY 25
#define EN8811H_TX_POL_NORMAL 0x1
@ -48,7 +43,7 @@
#define MII_MMD_ADDR_DATA_REG 0x0e
#define MMD_OP_MODE_DATA BIT(14)
#define EN8811H_DRIVER_VERSION "v1.3.0"
#define EN8811H_DRIVER_VERSION "v1.2.5"
#define LED_ON_CTRL(i) (0x024 + ((i)*2))
#define LED_ON_EN (1 << 15)
@ -88,64 +83,20 @@
#define LED_BLK_DUR (0x023)
#define LED_BLK_DUR_MASK (0xffff)
#define UNIT_LED_BLINK_DURATION 780
#define UNIT_LED_BLINK_DURATION 1024
#define GET_BIT(val, bit) ((val & BIT(bit)) >> bit)
#define INVALID_DATA 0xffff
#define PBUS_INVALID_DATA 0xffffffff
/* MII Registers */
#define AIR_AUX_CTRL_STATUS 0x1d
#define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2)
#define AIR_AUX_CTRL_STATUS_SPEED_100 0x4
#define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8
#define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc
/* Registers on BUCKPBUS */
#define EN8811H_2P5G_LPA 0x3b30
#define EN8811H_2P5G_LPA_2P5G BIT(0)
#define EN8811H_FW_CTRL_1 0x0f0018
#define EN8811H_FW_CTRL_1_START 0x0
#define EN8811H_FW_CTRL_1_FINISH 0x1
#define EN8811H_FW_CTRL_2 0x800000
#define EN8811H_FW_CTRL_2_LOADING BIT(11)
#define EN8811H_LOOP 0x800
#define NUM_ASI_REGS 5
struct air_cable_test_rsl {
int status[4];
unsigned int length[4];
};
struct en8811h_priv {
struct dentry *debugfs_root;
unsigned int dm_crc32;
unsigned int dsp_crc32;
unsigned int ivy_crc32;
char buf[512];
int pol;
int surge;
int cko;
struct kobject *cable_kobj;
int running_status;
int pair[4];
int an;
int link;
int speed;
int duplex;
int pause;
int asym_pause;
u16 on_crtl[3];
u16 blk_crtl[3];
u32 firmware_version;
bool mcu_needs_restart;
bool mcu_load;
int debug;
int phy_handle;
int init_stage;
int need_an;
int count;
};
struct air_base_t_led_cfg {
@ -155,18 +106,6 @@ struct air_base_t_led_cfg {
u16 on_cfg;
u16 blk_cfg;
};
enum air_init_stage {
AIR_INIT_START,
AIR_INIT_CONFIG,
AIR_INIT_FW_LOADING,
AIR_INIT_FW_READY,
AIR_INIT_SUCESS,
AIR_INIT_FW_FAIL,
AIR_INIT_FAIL,
AIR_INIT_LAST
};
enum air_led_gpio {
AIR_LED2_GPIO3 = 3,
AIR_LED1_GPIO4,

View File

@ -15,12 +15,10 @@
#define phydev_mdio_bus(_dev) (_dev->bus)
#define phydev_addr(_dev) (_dev->addr)
#define phydev_dev(_dev) (&_dev->dev)
#define phydev_kobj(_dev) (&_dev->dev.kobj)
#else
#define phydev_mdio_bus(_dev) (_dev->mdio.bus)
#define phydev_addr(_dev) (_dev->mdio.addr)
#define phydev_dev(_dev) (&_dev->mdio.dev)
#define phydev_kobj(_dev) (&_dev->mdio.dev.kobj)
#endif
#define DEBUGFS_COUNTER "counter"
@ -33,42 +31,8 @@
#define DEBUGFS_DBG_REG_SHOW "dbg_regs_show"
#define DEBUGFS_TEMPERATURE "temp"
#define DEBUGFS_LP_SPEED "lp_speed"
#define DEBUGFS_MII_CL22_OP "cl22_op"
#define DEBUGFS_MII_CL45_OP "cl45_op"
#define DEBUGFS_CABLE_DIAG "cable_diag"
#define DEBUGFS_LED_MODE "led_mode"
#define DEBUGFS_TX_COMP "tx_comp"
#define CMD_MAX_LENGTH 128
/* bits range: for example AIR_BITS_RANGE(16, 4) = 0x0F0000 */
#ifndef AIR_BITS_RANGE
#define AIR_BITS_RANGE(offset, range) GENMASK((offset) + (range) - 1U, (offset))
#endif /* End of AIR_BITS_RANGE */
/* bits offset right: for example AIR_BITS_OFF_R(0x1234, 8, 4) = 0x2 */
#ifndef AIR_BITS_OFF_R
#define AIR_BITS_OFF_R(val, offset, range) (((val) >> (offset)) & GENMASK((range) - 1U, 0))
#endif /* End of AIR_BITS_OFF_R */
/* bits offset left: for example AIR_BITS_OFF_L(0x1234, 8, 4) = 0x400 */
#ifndef AIR_BITS_OFF_L
#define AIR_BITS_OFF_L(val, offset, range) (((val) & GENMASK((range) - 1U, 0)) << (offset))
#endif /* End of AIR_BITS_OFF_L */
#define AIR_EN8811H_SET_VALUE(__out__, __val__, __offset__, __length__) \
{ \
(__out__) &= ~AIR_BITS_RANGE((__offset__), (__length__)); \
(__out__) |= AIR_BITS_OFF_L((__val__), (__offset__), (__length__)); \
}
#define CTL1000_PORT_TYPE (0x0400)
#define CTL1000_TEST_NORMAL (0x0000)
#define CTL1000_TEST_TM1 (0x2000)
#define CTL1000_TEST_TM2 (0x4000)
#define CTL1000_TEST_TM3 (0x6000)
#define CTL1000_TEST_TM4 (0x8000)
#define MMD_DEV_VSPEC1 (0x1e)
#define DEBUGFS_MII_CL22_OP "cl22_op"
#define DEBUGFS_MII_CL45_OP "cl45_op"
enum air_port_mode {
AIR_PORT_MODE_FORCE_100,
@ -100,104 +64,6 @@ enum air_link_mode_bit {
AIR_LINK_MODE_2500baseT_Full_BIT = 5,
};
enum air_led_force {
AIR_LED_NORMAL = 0,
AIR_LED_FORCE_OFF,
AIR_LED_FORCE_ON,
AIR_LED_FORCE_LAST = 0xff,
};
enum air_para {
AIR_PARA_PRIV,
AIR_PARA_PHYDEV,
AIR_PARA_LAST = 0xff
};
enum air_port_cable_status {
AIR_PORT_CABLE_STATUS_ERROR,
AIR_PORT_CABLE_STATUS_OPEN,
AIR_PORT_CABLE_STATUS_SHORT,
AIR_PORT_CABLE_STATUS_NORMAL,
AIR_PORT_CABLE_STATUS_LAST = 0xff
};
enum air_surge {
AIR_SURGE_0R,
AIR_SURGE_5R,
AIR_SURGE_LAST = 0xff
};
enum air_port_cable_test_pair {
AIR_PORT_CABLE_TEST_PAIR_A,
AIR_PORT_CABLE_TEST_PAIR_B,
AIR_PORT_CABLE_TEST_PAIR_C,
AIR_PORT_CABLE_TEST_PAIR_D,
AIR_PORT_CABLE_TEST_PAIR_ALL,
AIR_PORT_CABLE_TEST_PAIR_LAST
};
enum air_cko {
AIR_CKO_DIS,
AIR_CKO_EN,
AIR_CKO_LAST = 0xff
};
enum air_tx_comp_mode {
AIR_TX_COMP_MODE_100M_PAIR_A,
AIR_TX_COMP_MODE_100M_PAIR_B,
AIR_TX_COMP_MODE_100M_PAIR_A_DISCRETE,
AIR_TX_COMP_MODE_100M_PAIR_B_DISCRETE,
AIR_TX_COMP_MODE_1000M_TM1,
AIR_TX_COMP_MODE_1000M_TM2,
AIR_TX_COMP_MODE_1000M_TM3,
AIR_TX_COMP_MODE_1000M_TM4_TD,
AIR_TX_COMP_MODE_1000M_TM4_CM_PAIR_A,
AIR_TX_COMP_MODE_1000M_TM4_CM_PAIR_B,
AIR_TX_COMP_MODE_1000M_TM4_CM_PAIR_C,
AIR_TX_COMP_MODE_1000M_TM4_CM_PAIR_D,
AIR_TX_COMP_MODE_2500M_TM1,
AIR_TX_COMP_MODE_2500M_TM2,
AIR_TX_COMP_MODE_2500M_TM3,
AIR_TX_COMP_MODE_2500M_TM4_TONE_1,
AIR_TX_COMP_MODE_2500M_TM4_TONE_2,
AIR_TX_COMP_MODE_2500M_TM4_TONE_3,
AIR_TX_COMP_MODE_2500M_TM4_TONE_4,
AIR_TX_COMP_MODE_2500M_TM4_TONE_5,
AIR_TX_COMP_MODE_2500M_TM5,
AIR_TX_COMP_MODE_2500M_TM6,
AIR_TX_COMP_MODE_LAST = 0xFF,
};
struct trrg_param_s {
unsigned int TrRG_LSB :5;
unsigned int Reserved_21 :3;
unsigned int TrRG_MSB :5;
unsigned int Reserved_29 :3;
unsigned int Reserved_0 :1;
unsigned int DATA_ADDR :6;
unsigned int NODE_ADDR :4;
unsigned int CH_ADDR :2;
unsigned int WR_RD_CTRL :1;
unsigned int Reserved_14 :1;
unsigned int PKT_XMT_STA :1;
};
union trrgdesc_s {
struct trrg_param_s param;
unsigned short Raw[2];
unsigned int DescVal;
};
struct trrg_s {
union trrgdesc_s TrRGDesc;
unsigned int RgMask;
};
struct hal_tr_data_s {
unsigned short data_lo;
unsigned char data_hi;
};
#ifndef unlikely
# define unlikely(x) (x)
#endif
@ -218,10 +84,7 @@ unsigned int air_buckpbus_reg_read(struct phy_device *phydev,
int air_buckpbus_reg_write(struct phy_device *phydev,
unsigned int pbus_address, unsigned int pbus_data);
int en8811h_of_init(struct phy_device *phydev);
int air_surge_protect_cfg(struct phy_device *phydev);
int air_ref_clk_speed(struct phy_device *phydev, int para);
int air_cko_cfg(struct phy_device *phydev);
int airoha_control_flag(struct phy_device *phydev, int mask, int val);
int air_surge_5ohm_config(struct phy_device *phydev);
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
int airphy_debugfs_init(struct phy_device *phydev);
void airphy_debugfs_remove(struct phy_device *phydev);

File diff suppressed because it is too large Load Diff

View File

@ -19,10 +19,9 @@
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/crc32.h>
#include <linux/debugfs.h>
#include "air_en8811h_api.h"
#include "air_en8811h_fw.h"
#include "air_en8811h.h"
MODULE_DESCRIPTION("Airoha EN8811H PHY Drivers");
@ -35,11 +34,6 @@ MODULE_LICENSE("GPL");
* GPIO3 <-> BASE_T_LED2,
**************************/
/* User-defined.B */
/* #define AIR_MD32_FW_CHECK */
/* #define AIR_IVY_LOAD */
#ifdef AIR_IVY_LOAD
/* #define AIR_IVY_CHECK */
#endif
#define AIR_LED_SUPPORT
#ifdef AIR_LED_SUPPORT
static const struct air_base_t_led_cfg led_cfg[3] = {
@ -57,49 +51,8 @@ static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
/***********************************************************
* F U N C T I O N S
***********************************************************/
#ifdef AIR_MD32_FW_CHECK
static void air_mdio_read_buf(struct phy_device *phydev, unsigned long address,
const struct firmware *fw, unsigned int *crc32)
{
unsigned int offset;
int ret = 0;
unsigned int pbus_data_low, pbus_data_high;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
char *buf = kmalloc(fw->size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
memset(buf, '\0', fw->size);
/* page 4 */
ret |= air_mii_cl22_write(mbus, addr, 0x1F, 4);
/* address increment*/
ret |= air_mii_cl22_write(mbus, addr, 0x10, 0x8000);
ret |= air_mii_cl22_write(mbus, addr,
0x15, (unsigned int)((address >> 16) & 0xffff));
ret |= air_mii_cl22_write(mbus, addr,
0x16, (unsigned int)(address & 0xffff));
for (offset = 0; offset < fw->size; offset += 4) {
pbus_data_high = air_mii_cl22_read(mbus, addr, 0x17);
pbus_data_low = air_mii_cl22_read(mbus, addr, 0x18);
buf[offset + 0] = pbus_data_low & 0xff;
buf[offset + 1] = (pbus_data_low & 0xff00) >> 8;
buf[offset + 2] = pbus_data_high & 0xff;
buf[offset + 3] = (pbus_data_high & 0xff00) >> 8;
}
msleep(100);
*crc32 = ~crc32(~0, buf, fw->size);
ret |= air_mii_cl22_write(mbus, addr, 0x1F, 0);
kfree(buf);
if (ret) {
dev_info(dev, "%s 0x%lx FAIL(ret:%d)\n",
__func__, address, ret);
}
}
#endif
static int air_mdio_write_buf(struct phy_device *phydev,
unsigned long address, const struct firmware *fw)
static int air_mdio_write_buf(struct phy_device *phydev, unsigned long address,
unsigned long array_size, const unsigned char *buffer)
{
unsigned int write_data, offset;
int ret = 0;
@ -130,14 +83,14 @@ static int air_mdio_write_buf(struct phy_device *phydev,
return ret;
}
for (offset = 0; offset < fw->size; offset += 4) {
write_data = (fw->data[offset + 3] << 8) | fw->data[offset + 2];
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 = (fw->data[offset + 1] << 8) | fw->data[offset];
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);
@ -151,147 +104,14 @@ static int air_mdio_write_buf(struct phy_device *phydev,
}
return 0;
}
#ifdef AIR_IVY_LOAD
static int modify_reg_bits(struct phy_device *phydev,
unsigned int reg, unsigned int mask, unsigned int set)
{
unsigned int write_data;
int ret;
write_data = air_buckpbus_reg_read(phydev, reg);
write_data &= ~mask;
write_data |= set;
ret = air_buckpbus_reg_write(phydev, reg, write_data);
if (ret < 0)
return ret;
return 0;
}
static int air_mdio_load_ivy(struct phy_device *phydev,
unsigned long address, const struct firmware *fw)
{
unsigned int write_data = 0, offset, read_data;
int ret = 0, retry;
#ifdef AIR_IVY_CHECK
int error = 0;
#endif
struct device *dev = phydev_dev(phydev);
ret = air_buckpbus_reg_write(phydev,
0xcf924, 0x12);
if (ret < 0)
return ret;
write_data = air_buckpbus_reg_read(phydev, 0xcfa28);
write_data |= BIT(0);
ret = air_buckpbus_reg_write(phydev,
0xcfa28, write_data);
write_data = air_buckpbus_reg_read(phydev, 0xcfa28);
if (ret < 0)
return ret;
msleep(100);
for (offset = 0; offset < fw->size; offset += 4) {
write_data = (fw->data[offset + 3] << 24) | (fw->data[offset + 2] << 16);
write_data |= ((fw->data[offset + 1] << 8) | fw->data[offset]);
ret = air_buckpbus_reg_write(phydev,
address, write_data);
#ifdef AIR_IVY_CHECK
read_data = air_buckpbus_reg_read(phydev, address);
if (write_data != read_data) {
dev_info(dev, "%x: write_data(0x%x) != read_data(0x%x)\n",
address, write_data, read_data);
error++;
}
#endif
address += 1;
}
#ifdef AIR_IVY_CHECK
if (error)
dev_err(dev, "Check ivy Fail(%d)\n", error);
else
dev_err(dev, "Check ivy Pass\n");
#endif
ret = modify_reg_bits(phydev, 0xCFA28, BIT(0), 0);
if (ret < 0)
return ret;
ret = modify_reg_bits(phydev, 0xCFA28, 0, BIT(16));
if (ret < 0)
return ret;
ret |= air_buckpbus_reg_write(phydev,
0xDC065, 0x80);
ret |= air_buckpbus_reg_write(phydev,
0xDC064, 0x0);
if (ret < 0)
return ret;
retry = 5;
do {
msleep(300);
ret = air_buckpbus_reg_write(phydev,
0xDC064, 0x0);
if (ret < 0)
return ret;
write_data = air_buckpbus_reg_read(phydev, 0xDC065);
if (write_data == 0x80)
break;
if (!retry)
dev_err(dev, "0xDC065 is not ready.(0x%x)\n", write_data);
} while (retry--);
ret = modify_reg_bits(phydev, 0xCFA28, BIT(16), 0);
if (ret < 0)
return ret;
ret = modify_reg_bits(phydev, 0xCFA28, 0, BIT(24));
if (ret < 0)
return ret;
retry = 10;
do {
msleep(300);
write_data = air_buckpbus_reg_read(phydev, 0xCFA38);
if (write_data == EN8811H_PHY_IVY_READY) {
dev_info(dev, "IVY ready!\n");
break;
}
if (!retry)
dev_err(dev, "IVY is not ready.(0x%x)\n", write_data);
} while (retry--);
return 0;
}
#endif
static int en8811h_load_firmware(struct phy_device *phydev)
{
struct device *dev = phydev_dev(phydev);
const struct firmware *fw;
const char *firmware;
int ret = 0;
u32 pbus_value = 0;
#ifdef AIR_MD32_FW_CHECK
unsigned int d_crc32 = 0, crc32 = 0;
int retry = 0;
#endif
struct en8811h_priv *priv = phydev->priv;
priv->init_stage = AIR_INIT_FW_LOADING;
#ifdef AIR_IVY_LOAD
firmware = EN8811H_IVY;
ret = request_firmware_direct(&fw, firmware, dev);
if (ret < 0) {
dev_err(dev,
"failed to load firmware %s, ret: %d\n", firmware, ret);
return ret;
}
priv->ivy_crc32 = ~crc32(~0, fw->data, fw->size);
dev_info(dev, "%s: crc32=0x%x\n",
firmware, ~crc32(~0, fw->data, fw->size));
/* Download ivy */
ret = air_mdio_load_ivy(phydev, 0xd4000, fw);
release_firmware(fw);
if (ret < 0) {
dev_err(dev,
"air_mdio_write_buf 0xd4000 fail, ret: %d\n", ret);
goto release;
}
#endif
ret = air_buckpbus_reg_write(phydev,
0x0f0018, 0x0);
if (ret < 0)
@ -302,120 +122,29 @@ static int en8811h_load_firmware(struct phy_device *phydev)
0x800000, pbus_value);
if (ret < 0)
return ret;
firmware = EN8811H_MD32_DM;
ret = request_firmware_direct(&fw, firmware, dev);
if (ret < 0) {
dev_err(dev,
"failed to load firmware %s, ret: %d\n", firmware, ret);
return ret;
}
priv->dm_crc32 = ~crc32(~0, fw->data, fw->size);
dev_info(dev, "%s: crc32=0x%x\n",
firmware, ~crc32(~0, fw->data, fw->size));
/* Download DM */
ret = air_mdio_write_buf(phydev, 0x00000000, fw);
release_firmware(fw);
ret = air_mdio_write_buf(phydev, 0x00000000, EthMD32_dm_size, EthMD32_dm);
if (ret < 0) {
dev_err(dev,
"air_mdio_write_buf 0x00000000 fail, ret: %d\n", ret);
goto release;
}
firmware = EN8811H_MD32_DSP;
ret = request_firmware_direct(&fw, firmware, dev);
if (ret < 0) {
dev_info(dev,
"failed to load firmware %s, ret: %d\n", firmware, ret);
return ret;
}
priv->dsp_crc32 = ~crc32(~0, fw->data, fw->size);
dev_info(dev, "%s: crc32=0x%x\n",
firmware, ~crc32(~0, fw->data, fw->size));
/* Download PM */
ret = air_mdio_write_buf(phydev, 0x00100000, fw);
ret = air_mdio_write_buf(phydev, 0x00100000, EthMD32_pm_size, EthMD32_pm);
if (ret < 0) {
dev_err(dev,
"air_mdio_write_buf 0x00100000 fail , ret: %d\n", ret);
goto release;
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)
goto release;
#ifdef AIR_MD32_FW_CHECK
crc32 = ~crc32(~0, fw->data, fw->size);
/* Check PM */
air_mdio_read_buf(phydev, 0x100000, fw, &d_crc32);
if (d_crc32 == crc32)
dev_info(dev, "0x00100000 Check Sum Pass.\n");
else {
dev_info(dev, "0x00100000 Check Sum Fail.\n");
dev_info(dev, "CRC32 0x%x != Caculated CRC32 0x%x\n",
crc32, d_crc32);
}
release_firmware(fw);
retry = MAX_RETRY;
do {
ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x01);
if (ret < 0)
return ret;
msleep(100);
pbus_value = air_buckpbus_reg_read(phydev, 0x0f0018);
retry--;
if (retry == 0) {
dev_err(dev,
"Release Software Reset fail , ret: %d\n",
pbus_value);
goto release;
}
} while (pbus_value != 0x1);
dev_info(dev,
"Release Software Reset successful.\n");
#else
release_firmware(fw);
return ret;
ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x01);
if (ret < 0)
return ret;
#endif
return 0;
release:
release_firmware(fw);
return ret;
}
static int en8811h_init_up(struct phy_device *phydev)
{
int ret = 0, retry, reg_value;
struct device *dev = phydev_dev(phydev);
unsigned int pbus_value;
struct en8811h_priv *priv = phydev->priv;
dev_info(dev, "%s start\n", __func__);
ret = en8811h_load_firmware(phydev);
if (ret < 0) {
dev_err(dev, "EN8811H load firmware fail.\n");
return ret;
}
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");
priv->init_stage = AIR_INIT_FW_READY;
break;
}
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,
"%s fail!\n", __func__);
priv->init_stage = AIR_INIT_FW_FAIL;
}
} while (retry--);
return 0;
}
@ -491,7 +220,6 @@ static int en8811h_led_init(struct phy_device *phydev)
u16 cl45_data = led_dur;
int ret = 0, id;
struct device *dev = phydev_dev(phydev);
struct en8811h_priv *priv = phydev->priv;
ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_DUR, cl45_data);
if (ret < 0)
@ -527,10 +255,6 @@ static int en8811h_led_init(struct phy_device *phydev)
return ret;
}
}
priv->on_crtl[id] = air_mii_cl45_read(phydev, 0x1f,
LED_ON_CTRL(id));
priv->blk_crtl[id] = air_mii_cl45_read(phydev, 0x1f,
LED_BLK_CTRL(id));
}
reg_value = air_buckpbus_reg_read(phydev, 0xcf8b8) | led_gpio;
ret = air_buckpbus_reg_write(phydev, 0xcf8b8, reg_value);
@ -540,7 +264,6 @@ static int en8811h_led_init(struct phy_device *phydev)
return 0;
}
#endif /* AIR_LED_SUPPORT */
#if (KERNEL_VERSION(4, 5, 0) < LINUX_VERSION_CODE)
static int en8811h_get_features(struct phy_device *phydev)
{
@ -561,13 +284,11 @@ static int en8811h_get_features(struct phy_device *phydev)
phydev->supported);
linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
phydev->supported);
linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_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_2500baseT_Full_BIT,
linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
phydev->supported);
return 0;
}
@ -576,11 +297,12 @@ static int en8811h_get_features(struct phy_device *phydev)
static int en8811h_probe(struct phy_device *phydev)
{
int ret = 0;
int pid1 = 0, pid2 = 0;
u32 pbus_value = 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);
struct en8811h_priv *priv;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@ -590,30 +312,23 @@ static int en8811h_probe(struct phy_device *phydev)
ret = air_pbus_reg_write(phydev, 0xcf928, 0x0);
if (ret < 0)
goto priv_free;
pid1 = air_mii_cl22_read(mbus, addr, MII_PHYSID1);
pid2 = air_mii_cl22_read(mbus, addr, MII_PHYSID2);
dev_info(dev, "PHY = %x - %x\n", pid1, pid2);
if ((pid1 != EN8811H_PHY_ID1) || (pid2 != EN8811H_PHY_ID2)) {
dev_err(dev, "EN8811H dose not exist!!\n");
goto priv_free;
kfree(priv);
return -ENODEV;
}
priv->init_stage = AIR_INIT_START;
ret = air_buckpbus_reg_write(phydev, 0x1e00d0, 0xf);
ret |= air_buckpbus_reg_write(phydev, 0x1e0228, 0xf0);
if (ret < 0)
goto priv_free;
priv->mcu_needs_restart = false;
pbus_value = air_buckpbus_reg_read(phydev, 0xcf914);
dev_info(dev, "Bootmode: %s\n",
(GET_BIT(pbus_value, 24) ? "Flash" : "Download Code"));
ret = en8811h_of_init(phydev);
if (ret < 0)
goto priv_free;
ret = en8811h_load_firmware(phydev);
if (ret < 0) {
dev_err(dev, "EN8811H load firmware fail.\n");
goto priv_free;
}
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
ret = airphy_debugfs_init(phydev);
if (ret < 0) {
@ -622,68 +337,69 @@ static int en8811h_probe(struct phy_device *phydev)
goto priv_free;
}
#endif /* CONFIG_AIROHA_EN8811H_PHY_DEBUGFS */
if (priv->phy_handle) {
dev_info(dev, "EN8811H Probe OK! (%s)\n", EN8811H_DRIVER_VERSION);
} else {
ret = en8811h_init_up(phydev);
if (ret < 0)
goto priv_free;
priv->init_stage = AIR_INIT_CONFIG;
ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
if (ret < 0)
goto priv_free;
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
pbus_value &= ~0x3;
#if defined(CONFIG_OF)
pbus_value |= priv->pol;
#else
pbus_value |= (EN8811H_RX_POL_NORMAL | EN8811H_TX_POL_NORMAL);
#endif
ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
if (ret < 0)
goto priv_free;
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
dev_info(dev, "Tx, Rx Polarity : %08x\n", pbus_value);
priv->firmware_version = air_buckpbus_reg_read(phydev, 0x3b3c);
dev_info(dev, "MD32 FW Version : %08x\n", priv->firmware_version);
ret = air_surge_protect_cfg(phydev);
if (ret < 0) {
dev_err(dev,
"air_surge_protect_cfg fail. (ret=%d)\n", ret);
goto priv_free;
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;
}
ret = air_cko_cfg(phydev);
if (ret < 0) {
dev_err(dev,
"air_cko_cfg fail. (ret=%d)\n", ret);
goto priv_free;
}
#if defined(AIR_LED_SUPPORT)
ret = en8811h_led_init(phydev);
if (ret < 0) {
dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
goto priv_free;
}
#endif
priv->init_stage = AIR_INIT_SUCESS;
dev_info(dev, "EN8811H initialize OK! (%s)\n", EN8811H_DRIVER_VERSION);
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");
goto priv_free;
}
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
if (ret < 0)
goto priv_free;
/* Serdes polarity */
ret = en8811h_of_init(phydev);
if (ret < 0)
goto priv_free;
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
pbus_value &= ~0x3;
#if defined(CONFIG_OF)
pbus_value |= priv->pol;
#else
pbus_value |= (EN8811H_RX_POL_NORMAL | EN8811H_TX_POL_NORMAL);
#endif
ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
if (ret < 0)
goto priv_free;
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 (priv->surge) {
ret = air_surge_5ohm_config(phydev);
if (ret < 0)
dev_err(dev,
"air_surge_5ohm_config fail. (ret=%d)\n", ret);
} else
dev_info(dev, "Surge Protection Mode - 0R\n");
#if defined(AIR_LED_SUPPORT)
ret = en8811h_led_init(phydev);
if (ret < 0) {
dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
goto priv_free;
}
#endif
dev_info(dev, "EN8811H initialize OK! (%s)\n", EN8811H_DRIVER_VERSION);
return 0;
priv_free:
kfree(priv);
return ret;
}
void en8811h_remove(struct phy_device *phydev)
{
@ -700,229 +416,6 @@ void en8811h_remove(struct phy_device *phydev)
}
}
static int en8811h_restart_up(struct phy_device *phydev)
{
int ret, retry, reg_value;
u32 pbus_value;
struct device *dev = phydev_dev(phydev);
struct en8811h_priv *priv = phydev->priv;
dev_info(dev, "%s start\n", __func__);
ret = air_mii_cl45_write(phydev, 0x1e, 0x8009, 0x0);
if (ret < 0)
return ret;
ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
EN8811H_FW_CTRL_1_START);
if (ret < 0)
return ret;
ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
EN8811H_FW_CTRL_1_FINISH);
if (ret < 0)
return ret;
retry = MAX_RETRY;
do {
mdelay(300);
reg_value = air_mii_cl45_read(phydev, 0x1e, 0x8009);
if (reg_value == EN8811H_PHY_READY) {
priv->init_stage = AIR_INIT_FW_READY;
dev_info(dev, "EN8811H PHY ready!\n");
break;
}
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,
"%s fail!\n", __func__);
priv->init_stage = AIR_INIT_FW_FAIL;
}
} while (retry--);
return 0;
}
static int en8811h_config_init(struct phy_device *phydev)
{
int ret = 0;
u32 pbus_value = 0;
struct device *dev = phydev_dev(phydev);
struct en8811h_priv *priv = phydev->priv;
ret = air_buckpbus_reg_write(phydev, 0x1e00d0, 0xf);
ret |= air_buckpbus_reg_write(phydev, 0x1e0228, 0xf0);
if (ret < 0)
return ret;
/* If restart happened in .probe(), no need to restart now */
if (priv->mcu_needs_restart) {
ret = en8811h_restart_up(phydev);
if (ret < 0)
goto priv_free;
} else {
ret = en8811h_init_up(phydev);
if (ret < 0)
goto priv_free;
/* Next calls to .config_init() mcu needs to restart */
priv->mcu_needs_restart = true;
}
priv->init_stage = AIR_INIT_CONFIG;
ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
ret |= air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
if (ret < 0)
goto priv_free;
/* Serdes polarity */
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
pbus_value &= ~0x3;
#if defined(CONFIG_OF)
pbus_value |= priv->pol;
#else
pbus_value |= (EN8811H_RX_POL_NORMAL | EN8811H_TX_POL_NORMAL);
#endif
ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
if (ret < 0)
goto priv_free;
pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
dev_info(dev, "Tx, Rx Polarity : %08x\n", pbus_value);
priv->firmware_version = air_buckpbus_reg_read(phydev, 0x3b3c);
dev_info(dev, "MD32 FW Version : %08x\n", priv->firmware_version);
ret = air_surge_protect_cfg(phydev);
if (ret < 0) {
dev_err(dev,
"air_surge_protect_cfg fail. (ret=%d)\n", ret);
goto priv_free;
}
ret = air_cko_cfg(phydev);
if (ret < 0) {
dev_err(dev,
"air_cko_cfg fail. (ret=%d)\n", ret);
goto priv_free;
}
#if defined(AIR_LED_SUPPORT)
ret = en8811h_led_init(phydev);
if (ret < 0) {
dev_err(dev, "en8811h_led_init fail. (ret=%d)\n", ret);
goto priv_free;
}
#endif
priv->init_stage = AIR_INIT_SUCESS;
dev_info(dev, "EN8811H initialize OK! (%s)\n", EN8811H_DRIVER_VERSION);
return 0;
priv_free:
kfree(priv);
return ret;
}
static int en8811h_get_rate_matching(struct phy_device *phydev,
phy_interface_t iface)
{
return RATE_MATCH_PAUSE;
}
static int en8811h_config_aneg(struct phy_device *phydev)
{
bool changed = false;
int err, val;
val = 0;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
phydev->advertising))
val |= MDIO_AN_10GBT_CTRL_ADV2_5G;
err = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
MDIO_AN_10GBT_CTRL_ADV2_5G, val);
if (err < 0)
return err;
if (err > 0)
changed = true;
return __genphy_config_aneg(phydev, changed);
}
static int en8811h_update_link(struct phy_device *phydev)
{
int status = 0, bmcr;
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
bmcr = air_mii_cl22_read(mbus, addr, MII_BMCR);
if (bmcr < 0)
return bmcr;
/* Autoneg is being started, therefore disregard BMSR value and
* report link as down.
*/
if (bmcr & BMCR_ANRESTART)
goto done;
status = air_mii_cl22_read(mbus, addr, MII_BMSR);
if (status < 0)
return status;
done:
phydev->link = status & BMSR_LSTATUS ? 1 : 0;
phydev->autoneg_complete = status & BMSR_ANEGCOMPLETE ? 1 : 0;
return 0;
}
static int en8811h_read_status(struct phy_device *phydev)
{
struct en8811h_priv *priv = phydev->priv;
u32 pbus_value;
int old_link = phydev->link, ret;
ret = en8811h_update_link(phydev);
if (ret)
return ret;
/* why bother the PHY if nothing can have changed */
if (old_link && phydev->link)
return 0;
phydev->speed = SPEED_UNKNOWN;
phydev->duplex = DUPLEX_UNKNOWN;
phydev->pause = 0;
phydev->asym_pause = 0;
phydev->rate_matching = RATE_MATCH_PAUSE;
ret = genphy_read_lpa(phydev);
if (ret < 0)
return ret;
/* Get link partner 2.5GBASE-T ability from vendor register */
pbus_value = air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA);
if (ret < 0)
return ret;
linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
phydev->lp_advertising,
pbus_value & EN8811H_2P5G_LPA_2P5G);
phydev->duplex = DUPLEX_FULL;
if (phydev->autoneg_complete)
phy_resolve_aneg_pause(phydev);
if (!phydev->link)
return 0;
ret = air_ref_clk_speed(phydev, AIR_PARA_PHYDEV);
if (ret < 0)
return ret;
/* Firmware before version 24011202 has no vendor register 2P5G_LPA.
* Assume link partner advertised it if connected at 2500Mbps.
*/
if (priv->firmware_version < 0x24011202) {
linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
phydev->lp_advertising,
phydev->speed == SPEED_2500);
}
if (phydev->speed <= SPEED_1000)
phydev->pause = 1;
return 0;
}
static struct phy_driver en8811h_driver[] = {
{
.phy_id = EN8811H_PHY_ID,
@ -935,12 +428,6 @@ static struct phy_driver en8811h_driver[] = {
.read_mmd = __air_mii_cl45_read,
.write_mmd = __air_mii_cl45_write,
#endif
.config_init = en8811h_config_init,
.read_status = en8811h_read_status,
.get_rate_matching = en8811h_get_rate_matching,
.config_aneg = en8811h_config_aneg,
.resume = genphy_resume,
.suspend = genphy_suspend,
} };
int __init en8811h_phy_driver_register(void)

File diff suppressed because it is too large Load Diff