372 lines
11 KiB
C
372 lines
11 KiB
C
/*
|
||
* Copyright : (C) 2022 Phytium Information Technology, Inc.
|
||
* All Rights Reserved.
|
||
*
|
||
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
|
||
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
|
||
* either version 1.0 of the License, or (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
* See the Phytium Public License for more details.
|
||
*
|
||
*
|
||
* FilePath: fxmac_phy.c
|
||
* Date: 2022-04-06 14:46:52
|
||
* LastEditTime: 2022-04-06 14:46:58
|
||
* Description: This file is for
|
||
*
|
||
* Modify History:
|
||
* Ver Who Date Changes
|
||
* ----- ------ -------- --------------------------------------
|
||
*/
|
||
|
||
#include "fxmac.h"
|
||
#include "eth_ieee_reg.h"
|
||
#include "fdebug.h"
|
||
|
||
#if defined(CONFIG_FXMAC_PHY_YT)
|
||
#include "phy_yt.h"
|
||
#endif
|
||
|
||
|
||
#define FXMAC_DEBUG_TAG "FXMAC_PHY"
|
||
#define FXMAC_ERROR(format, ...) FT_DEBUG_PRINT_E(FXMAC_DEBUG_TAG, format, ##__VA_ARGS__)
|
||
#define FXMAC_INFO(format, ...) FT_DEBUG_PRINT_I(FXMAC_DEBUG_TAG, format, ##__VA_ARGS__)
|
||
#define FXMAC_DEBUG(format, ...) FT_DEBUG_PRINT_D(FXMAC_DEBUG_TAG, format, ##__VA_ARGS__)
|
||
#define FXMAC_WARN(format, ...) FT_DEBUG_PRINT_W(FXMAC_DEBUG_TAG, format, ##__VA_ARGS__)
|
||
|
||
static FXmac *instance_b;
|
||
static u32 phy_addr_b;
|
||
|
||
static FError FXmacDetect(FXmac *instance_p, u32 *phy_addr_p)
|
||
{
|
||
u32 phy_addr = 0, i = 0, index;
|
||
u16 phy_reg = 0, phy_id1_reg, phy_id2_reg;
|
||
FError ret;
|
||
instance_b = instance_p;
|
||
|
||
for (phy_addr = 0; phy_addr < FT_XMAC_PHY_MAX_NUM; phy_addr++)
|
||
{
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_STATUS_REG_OFFSET, &phy_reg);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s, PHY operation is busy", __func__);
|
||
return ret;
|
||
}
|
||
FXMAC_INFO("PHY_STATUS_REG_OFFSET is %x \r\n", phy_reg);
|
||
if (phy_reg != 0xffff)
|
||
{
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_IDENTIFIER_1_REG, &phy_id1_reg);
|
||
ret |= FXmacPhyRead(instance_p, phy_addr, PHY_IDENTIFIER_2_REG, &phy_id2_reg);
|
||
FXMAC_INFO("phy_id1_reg is 0x%x \r\n", phy_id1_reg);
|
||
FXMAC_INFO("phy_id2_reg is 0x%x \r\n", phy_id2_reg);
|
||
if ((ret == FT_SUCCESS) && (phy_id2_reg != 0) && (phy_id1_reg != 0xffff) && (phy_id1_reg != 0xffff))
|
||
{
|
||
*phy_addr_p = phy_addr;
|
||
phy_addr_b = phy_addr;
|
||
FXMAC_INFO("phy_addr is 0x%x \r\n", phy_addr);
|
||
return FT_SUCCESS;
|
||
}
|
||
}
|
||
}
|
||
|
||
return FT_SUCCESS;
|
||
}
|
||
|
||
static FError FXmacGetIeeePhySpeed(FXmac *instance_p, u32 phy_addr)
|
||
{
|
||
u16 temp, temp2;
|
||
u16 control;
|
||
u16 status;
|
||
u16 partner_capabilities;
|
||
u32 negotitation_timeout_cnt = 0;
|
||
FError ret;
|
||
volatile s32 wait;
|
||
|
||
FXMAC_INFO("Start PHY autonegotiation ");
|
||
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_CONTROL_REG_OFFSET, &control);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,read PHY_CONTROL_REG_OFFSET is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
control |= PHY_CONTROL_RESET_MASK;
|
||
|
||
ret = FXmacPhyWrite(instance_p, phy_addr, PHY_CONTROL_REG_OFFSET, control);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,write PHY_CONTROL_REG_OFFSET is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
for (wait = 0; wait < 100000; wait++)
|
||
;
|
||
FXMAC_INFO(" PHY reset end ");
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_CONTROL_REG_OFFSET, &control);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,read PHY_CONTROL_REG_OFFSET is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
control |= PHY_CONTROL_AUTONEGOTIATE_ENABLE;
|
||
control |= PHY_CONTROL_AUTONEGOTIATE_RESTART;
|
||
ret = FXmacPhyWrite(instance_p, phy_addr, PHY_CONTROL_REG_OFFSET, control);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,write PHY_CONTROL_REG_OFFSET is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
FXMAC_INFO("Waiting for PHY to complete autonegotiation.");
|
||
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_STATUS_REG_OFFSET, &status);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,read PHY_CONTROL_REG_OFFSET is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
|
||
while (!(status & PHY_STATUS_AUTONEGOTIATE_COMPLETE))
|
||
{
|
||
for (wait = 0; wait < 1000000; wait++)
|
||
;
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_STATUS_REG_OFFSET, &status);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,read PHY_STATUS_REG_OFFSET is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
|
||
if (negotitation_timeout_cnt++ >= 0xfff)
|
||
{
|
||
FXMAC_ERROR("autonegotiation is error ");
|
||
return FXMAC_PHY_AUTO_AUTONEGOTIATION_FAILED;
|
||
}
|
||
}
|
||
FXMAC_INFO("autonegotiation complete ");
|
||
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_SPECIFIC_STATUS_REG, &temp);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,read PHY_SPECIFIC_STATUS_REG is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
FXMAC_INFO("temp is %x \r\n", temp);
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_STATUS_REG_OFFSET, &temp2);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,read PHY_STATUS_REG_OFFSET is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
FXMAC_INFO("temp2 is %x \r\n", temp2);
|
||
|
||
if (temp & (1 << 13))
|
||
{
|
||
FXMAC_INFO("duplex is full \r\n");
|
||
instance_p->config.duplex = 1;
|
||
}
|
||
else
|
||
{
|
||
FXMAC_INFO("duplex is half \r\n");
|
||
instance_p->config.duplex = 0;
|
||
}
|
||
|
||
if ((temp & 0xC000) == PHY_SPECIFIC_STATUS_SPEED_1000M)
|
||
{
|
||
FXMAC_INFO("speed is 1000\r\n");
|
||
instance_p->config.speed = 1000;
|
||
}
|
||
else if ((temp & 0xC000) == PHY_SPECIFIC_STATUS_SPEED_100M)
|
||
{
|
||
FXMAC_INFO("speed is 100\r\n");
|
||
instance_p->config.speed = 100;
|
||
}
|
||
else
|
||
{
|
||
FXMAC_INFO("speed is 10\r\n");
|
||
instance_p->config.speed = 10;
|
||
}
|
||
|
||
return FT_SUCCESS;
|
||
}
|
||
|
||
void FxmaxLinkupCheck(void)
|
||
{
|
||
u16 temp;
|
||
FXmacPhyRead(instance_b, phy_addr_b, PHY_SPECIFIC_STATUS_REG, &temp);
|
||
FXMAC_INFO("0x17 value is %x \r\n", temp);
|
||
FXMAC_INFO("linkup status is %x \r\n", temp & (1 << 10));
|
||
}
|
||
|
||
|
||
static FError FXmacConfigureIeeePhySpeed(FXmac *instance_p, u32 phy_addr, u32 speed, u32 duplex_mode)
|
||
{
|
||
u16 control;
|
||
u16 autonereg;
|
||
volatile s32 wait;
|
||
FError ret;
|
||
u16 specific_reg = 0;
|
||
|
||
FXMAC_INFO("manual setting ,phy_addr is %d,speed %d, duplex_mode is %d \r\n", phy_addr, speed, duplex_mode);
|
||
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_AUTONEGO_ADVERTISE_REG, &autonereg);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,read PHY_AUTONEGO_ADVERTISE_REG is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
autonereg |= PHY_AUTOADVERTISE_ASYMMETRIC_PAUSE_MASK;
|
||
autonereg |= PHY_AUTOADVERTISE_PAUSE_MASK;
|
||
ret = FXmacPhyWrite(instance_p, phy_addr, PHY_AUTONEGO_ADVERTISE_REG, autonereg);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,write PHY_AUTONEGO_ADVERTISE_REG is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_CONTROL_REG_OFFSET, &control);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,read PHY_AUTONEGO_ADVERTISE_REG is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
FXMAC_INFO("PHY_CONTROL_REG_OFFSET is %x \r\n", control);
|
||
|
||
|
||
control &= ~PHY_CONTROL_LINKSPEED_1000M;
|
||
control &= ~PHY_CONTROL_LINKSPEED_100M;
|
||
control &= ~PHY_CONTROL_LINKSPEED_10M;
|
||
|
||
if (speed == 1000)
|
||
{
|
||
control |= PHY_CONTROL_LINKSPEED_1000M;
|
||
}
|
||
else if (speed == 100)
|
||
{
|
||
control |= PHY_CONTROL_LINKSPEED_100M;
|
||
}
|
||
else if (speed == 10)
|
||
{
|
||
control |= PHY_CONTROL_LINKSPEED_10M;
|
||
}
|
||
|
||
if (duplex_mode == 1)
|
||
{
|
||
control |= PHY_CONTROL_FULL_DUPLEX_MASK;
|
||
}
|
||
else
|
||
{
|
||
control &= ~PHY_CONTROL_FULL_DUPLEX_MASK;
|
||
}
|
||
|
||
/* disable auto-negotiation */
|
||
control &= ~(PHY_CONTROL_AUTONEGOTIATE_ENABLE);
|
||
control &= ~(PHY_CONTROL_AUTONEGOTIATE_RESTART);
|
||
|
||
ret = FXmacPhyWrite(instance_p, phy_addr, PHY_CONTROL_REG_OFFSET, control); /* Technology Ability Field */
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,write PHY_AUTONEGO_ADVERTISE_REG is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
for (wait = 0; wait < 100000; wait++)
|
||
;
|
||
|
||
FXMAC_INFO("Manual selection completed \r\n");
|
||
|
||
ret = FXmacPhyRead(instance_p, phy_addr, PHY_SPECIFIC_STATUS_REG, &specific_reg);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("%s line is %d,read PHY_SPECIFIC_STATUS_REG is error", __func__, __LINE__);
|
||
return ret;
|
||
}
|
||
|
||
FXMAC_INFO("specific_reg is %x \r\n", specific_reg);
|
||
|
||
if (specific_reg & (1 << 13))
|
||
{
|
||
FXMAC_INFO("duplex is full \r\n");
|
||
instance_p->config.duplex = 1;
|
||
}
|
||
else
|
||
{
|
||
FXMAC_INFO("duplex is half \r\n");
|
||
instance_p->config.duplex = 0;
|
||
}
|
||
|
||
if ((specific_reg & 0xC000) == PHY_SPECIFIC_STATUS_SPEED_1000M)
|
||
{
|
||
FXMAC_INFO("speed is 1000\r\n");
|
||
instance_p->config.speed = 1000;
|
||
}
|
||
else if ((specific_reg & 0xC000) == PHY_SPECIFIC_STATUS_SPEED_100M)
|
||
{
|
||
FXMAC_INFO("speed is 100\r\n");
|
||
instance_p->config.speed = 100;
|
||
}
|
||
else
|
||
{
|
||
FXMAC_INFO("speed is 10\r\n");
|
||
instance_p->config.speed = 10;
|
||
}
|
||
|
||
return FT_SUCCESS;
|
||
}
|
||
|
||
/**
|
||
* @name: FXmacPhyInit
|
||
* @msg: setup the PHYs for proper speed setting.
|
||
* @param {FXmac} *instance_p is a pointer to the instance to be worked on.
|
||
* @param {u32} speed is phy operating speed
|
||
* @param {u32} phy_addr is the address of the PHY to be read (supports multiple PHYs)
|
||
* @param {u32} duplex_mode is The duplex mode can be selected via either the Auto-Negotiation process or manual duplex selection.
|
||
* @param {u32} autonegotiation_en is an auto-negotiated flag . 1 is enable auto ,0 is manual
|
||
* @return {FError}
|
||
*/
|
||
FError FXmacPhyInit(FXmac *instance_p, u32 speed, u32 duplex_mode, u32 autonegotiation_en)
|
||
{
|
||
FError ret;
|
||
u32 index = 0, phy_mask;
|
||
u16 phy_identity;
|
||
u32 phy_addr;
|
||
|
||
if (FXmacDetect(instance_p, &phy_addr) != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("phy is not found");
|
||
return FXMAC_PHY_IS_NOT_FOUND;
|
||
}
|
||
FXMAC_INFO("settings phy_addr is %d\n", phy_addr);
|
||
instance_p->phy_address = phy_addr;
|
||
if (autonegotiation_en)
|
||
{
|
||
ret = FXmacGetIeeePhySpeed(instance_p, phy_addr);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
return ret;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
FXMAC_INFO("Set the communication speed manually");
|
||
ret = FXmacConfigureIeeePhySpeed(instance_p, phy_addr, speed, duplex_mode);
|
||
if (ret != FT_SUCCESS)
|
||
{
|
||
FXMAC_ERROR("Failed to manually set the PHY");
|
||
return ret;
|
||
}
|
||
|
||
}
|
||
|
||
instance_p->link_status = FXMAC_LINKUP;
|
||
return FT_SUCCESS;
|
||
}
|