blob: 43bb27a50423af51e361a7ceb6480e40b76bb5cd [file] [log] [blame]
/*
* Copyright (c) 2018, 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*qca808x_start*/
#include "sw.h"
#include "fal_port_ctrl.h"
#include "hsl_api.h"
#include "hsl.h"
#include "hsl_phy.h"
#include "ssdk_plat.h"
#include "qca808x_phy.h"
/*qca808x_end*/
#if defined(IN_PTP)
#include "qca808x_ptp.h"
#endif
#include "qca808x.h"
#ifdef IN_LED
#include "qca808x_led.h"
#endif
static a_bool_t phy_dev_drv_init_flag = A_FALSE;
/*qca808x_start*/
static a_bool_t phy_ops_flag = A_FALSE;
static struct mutex qca808x_reg_lock;
#define QCA808X_LOCKER_INIT mutex_init(&qca808x_reg_lock)
#define QCA808X_REG_LOCK mutex_lock(&qca808x_reg_lock)
#define QCA808X_REG_UNLOCK mutex_unlock(&qca808x_reg_lock)
/******************************************************************************
*
* qca808x_phy_mii_read - mii register read
*
* mii register read
*/
a_uint16_t
qca808x_phy_reg_read(a_uint32_t dev_id, a_uint32_t phy_id, a_uint32_t reg_id)
{
sw_error_t rv = SW_OK;
a_uint16_t phy_data = 0;
#if defined(IN_PHY_I2C_MODE)
a_uint32_t port_id = qca_ssdk_phy_addr_to_port(dev_id, phy_id);
a_uint8_t phy_access_type = hsl_port_phy_access_type_get(dev_id, port_id);
if (phy_access_type == PHY_I2C_ACCESS) {
HSL_PHY_I2C_GET(rv, dev_id, phy_id, reg_id, &phy_data);
}
else
#endif
{
HSL_PHY_GET(rv, dev_id, phy_id, reg_id, &phy_data);
}
if (rv != SW_OK) {
return PHY_INVALID_DATA;
}
return phy_data;
}
/******************************************************************************
*
* qca808x_phy_mii_write - mii register write
*
* mii register write
*/
sw_error_t
qca808x_phy_reg_write(a_uint32_t dev_id, a_uint32_t phy_id, a_uint32_t reg_id,
a_uint16_t reg_val)
{
sw_error_t rv;
#if defined(IN_PHY_I2C_MODE)
a_uint32_t port_id = qca_ssdk_phy_addr_to_port(dev_id, phy_id);
a_uint8_t phy_access_type = hsl_port_phy_access_type_get(dev_id, port_id);
if (phy_access_type == PHY_I2C_ACCESS) {
HSL_PHY_I2C_SET(rv, dev_id, phy_id, reg_id, reg_val);
}
else
#endif
{
HSL_PHY_SET(rv, dev_id, phy_id, reg_id, reg_val);
}
return rv;
}
/******************************************************************************
*
* qca808x_phy_debug_write - debug port write
*
* debug port write
*/
sw_error_t
qca808x_phy_debug_write(a_uint32_t dev_id, a_uint32_t phy_id, a_uint16_t reg_id,
a_uint16_t reg_val)
{
sw_error_t rv = SW_OK;
QCA808X_REG_LOCK;
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_DEBUG_PORT_ADDRESS, reg_id);
if (rv != SW_OK)
{
QCA808X_REG_UNLOCK;
SSDK_ERROR("qca808x_phy_reg_write failed\n");
return SW_FAIL;
}
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_DEBUG_PORT_DATA, reg_val);
if (rv != SW_OK)
{
QCA808X_REG_UNLOCK;
SSDK_ERROR("qca808x_phy_reg_write failed\n");
return SW_FAIL;
}
QCA808X_REG_UNLOCK;
return rv;
}
/******************************************************************************
*
* qca808x_phy_debug_read - debug port read
*
* debug port read
*/
a_uint16_t
qca808x_phy_debug_read(a_uint32_t dev_id, a_uint32_t phy_id, a_uint16_t reg_id)
{
sw_error_t rv = SW_OK;
a_uint16_t phy_data = 0;
QCA808X_REG_LOCK;
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_DEBUG_PORT_ADDRESS, reg_id);
if (rv != SW_OK) {
QCA808X_REG_UNLOCK;
SSDK_DEBUG("qca808x_phy_reg_write failed\n");
return PHY_INVALID_DATA;
}
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_DEBUG_PORT_DATA);
if (phy_data == PHY_INVALID_DATA) {
QCA808X_REG_UNLOCK;
SSDK_DEBUG("qca808x_phy_reg_read failed\n");
return PHY_INVALID_DATA;
}
QCA808X_REG_UNLOCK;
return phy_data;
}
/******************************************************************************
*
* qca808x_phy_mmd_write - PHY MMD register write
*
* PHY MMD register write
*/
sw_error_t
qca808x_phy_mmd_write(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint16_t mmd_num, a_uint16_t reg_id, a_uint16_t reg_val)
{
sw_error_t rv;
a_uint32_t reg_id_c45 = QCA808X_REG_C45_ADDRESS(mmd_num, reg_id);
#if defined(IN_PHY_I2C_MODE)
a_uint32_t port_id = qca_ssdk_phy_addr_to_port(dev_id, phy_id);
a_uint8_t phy_access_type = hsl_port_phy_access_type_get(dev_id, port_id);
if (phy_access_type == PHY_I2C_ACCESS) {
HSL_PHY_I2C_SET(rv, dev_id, phy_id, reg_id_c45, reg_val);
}
else
#endif
{
HSL_PHY_SET(rv, dev_id, phy_id, reg_id_c45, reg_val);
}
return rv;
}
/******************************************************************************
*
* qca808x_phy_mmd_read - PHY MMD register read
*
* PHY MMD register read
*/
a_uint16_t
qca808x_phy_mmd_read(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint16_t mmd_num, a_uint16_t reg_id)
{
sw_error_t rv = SW_OK;
a_uint16_t phy_data = 0;
a_uint32_t reg_id_c45 = QCA808X_REG_C45_ADDRESS(mmd_num, reg_id);
#if defined(IN_PHY_I2C_MODE)
a_uint32_t port_id = qca_ssdk_phy_addr_to_port(dev_id, phy_id);
a_uint8_t phy_access_type = hsl_port_phy_access_type_get(dev_id, port_id);
if (phy_access_type == PHY_I2C_ACCESS) {
HSL_PHY_I2C_GET(rv, dev_id, phy_id, reg_id_c45, &phy_data);
}
else
#endif
{
HSL_PHY_GET(rv, dev_id, phy_id, reg_id_c45, &phy_data);
}
if (rv != SW_OK) {
return PHY_INVALID_DATA;
}
return phy_data;
}
static sw_error_t
qca808x_phy_ms_random_seed_set(a_uint32_t dev_id, a_uint32_t phy_id)
{
a_uint16_t phy_data;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_debug_read(dev_id, phy_id,
QCA808X_DEBUG_LOCAL_SEED);
phy_data &= ~(QCA808X_MASTER_SLAVE_SEED_CFG);
phy_data |= (prandom_u32()%QCA808X_MASTER_SLAVE_SEED_RANGE) << 2;
SSDK_DEBUG("QCA808X_DEBUG_LOCAL_SEED:%x\n", phy_data);
rv = qca808x_phy_debug_write(dev_id, phy_id,
QCA808X_DEBUG_LOCAL_SEED, phy_data);
return rv;
}
static sw_error_t
qca808x_phy_ms_seed_enable(a_uint32_t dev_id, a_uint32_t phy_id,
a_bool_t enable)
{
a_uint16_t phy_data;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_debug_read(dev_id, phy_id,
QCA808X_DEBUG_LOCAL_SEED);
if(enable)
{
phy_data |= QCA808X_MASTER_SLAVE_SEED_ENABLE;
}
else
{
phy_data &= ~(QCA808X_MASTER_SLAVE_SEED_ENABLE);
}
rv = qca808x_phy_debug_write(dev_id, phy_id,
QCA808X_DEBUG_LOCAL_SEED, phy_data);
return rv;
}
a_bool_t
qca808x_phy_2500caps(a_uint32_t dev_id, a_uint32_t phy_id)
{
a_uint16_t phy_data;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD1_NUM,
QCA808X_MMD1_PMA_CAP_REG);
if (phy_data & QCA808X_STATUS_2500T_FD_CAPS) {
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_CHIP_TYPE);
if(!(phy_data & QCA808X_PHY_1G_CHIP_TYPE))
return A_TRUE;
}
return A_FALSE;
}
/******************************************************************************
*
* qca808x_phy_get status
*
* get phy status
*/
sw_error_t
qca808x_phy_get_status(a_uint32_t dev_id, a_uint32_t phy_id,
struct port_phy_status *phy_status)
{
a_uint16_t phy_data;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_SPEC_STATUS);
PHY_RTN_ON_READ_ERROR(phy_data);
/*get phy link status*/
if (phy_data & QCA808X_STATUS_LINK_PASS) {
phy_status->link_status = A_TRUE;
}
else {
phy_status->link_status = A_FALSE;
if (qca808x_phy_2500caps(dev_id, phy_id) == A_TRUE) {
SW_RTN_ON_ERROR(
qca808x_phy_ms_random_seed_set (dev_id, phy_id));
/*protect logic, if MASTER_SLAVE_CONFIG_FAULT is 1,
then disable this logic*/
phy_data = qca808x_phy_reg_read(dev_id, phy_id,
QCA808X_1000BASET_STATUS);
if ((phy_data & QCA808X_MASTER_SLAVE_CONFIG_FAULT) >> 15)
{
SW_RTN_ON_ERROR(
qca808x_phy_ms_seed_enable (dev_id, phy_id, A_FALSE));
SSDK_INFO("master_slave_config_fault was set\n");
}
}
return SW_OK;
}
/*get phy speed*/
switch (phy_data & QCA808X_STATUS_SPEED_MASK) {
case QCA808X_STATUS_SPEED_2500MBS:
phy_status->speed = FAL_SPEED_2500;
break;
case QCA808X_STATUS_SPEED_1000MBS:
phy_status->speed = FAL_SPEED_1000;
break;
case QCA808X_STATUS_SPEED_100MBS:
phy_status->speed = FAL_SPEED_100;
break;
case QCA808X_STATUS_SPEED_10MBS:
phy_status->speed = FAL_SPEED_10;
break;
default:
return SW_READ_ERROR;
}
/*get phy duplex*/
if (phy_data & QCA808X_STATUS_FULL_DUPLEX) {
phy_status->duplex = FAL_FULL_DUPLEX;
} else {
phy_status->duplex = FAL_HALF_DUPLEX;
}
/* get phy flowctrl resolution status */
if (phy_data & QCA808X_PHY_RX_FLOWCTRL_STATUS) {
phy_status->rx_flowctrl = A_TRUE;
} else {
phy_status->rx_flowctrl = A_FALSE;
}
if (phy_data & QCA808X_PHY_TX_FLOWCTRL_STATUS) {
phy_status->tx_flowctrl = A_TRUE;
} else {
phy_status->tx_flowctrl = A_FALSE;
}
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_get_speed - Determines the speed of phy ports associated with the
* specified device.
*/
sw_error_t
qca808x_phy_get_speed(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_speed_t * speed)
{
sw_error_t rv = SW_OK;
struct port_phy_status phy_status = {0};
rv = qca808x_phy_get_status(dev_id, phy_id, &phy_status);
PHY_RTN_ON_ERROR(rv);
if (phy_status.link_status == A_TRUE) {
*speed = phy_status.speed;
} else {
*speed = FAL_SPEED_10;
}
return rv;
}
/******************************************************************************
*
* qca808x_phy_set_force_speed - Force the speed of qca808x phy ports associated with the
* specified device.
*/
sw_error_t
qca808x_phy_set_force_speed(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_speed_t speed)
{
a_uint16_t phy_data1 = 0;
a_uint16_t phy_data2 = 0;
sw_error_t rv = SW_OK;
/* the speed of qca808x controled by MMD1 PMA/PMD control register */
phy_data1 = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD1_NUM,
QCA808X_PHY_MMD1_PMA_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data1);
phy_data1 &= ~QCA808X_PMA_CONTROL_SPEED_MASK;
phy_data2 = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD1_NUM,
QCA808X_PHY_MMD1_PMA_TYPE);
PHY_RTN_ON_READ_ERROR(phy_data2);
phy_data2 &= ~QCA808X_PMA_TYPE_MASK;
switch(speed)
{
#if 0
case FAL_SPEED_2500:
if(!qca808x_phy_2500caps(dev_id, phy_id))
return SW_NOT_SUPPORTED;
phy_data1 |= QCA808X_PMA_CONTROL_2500M;
phy_data2 |= QCA808X_PMA_TYPE_2500M;
break;
#endif
case FAL_SPEED_1000:
phy_data1 |= QCA808X_PMA_CONTROL_1000M;
phy_data2 |= QCA808X_PMA_TYPE_1000M;
break;
case FAL_SPEED_100:
phy_data1 |= QCA808X_PMA_CONTROL_100M;
phy_data2 |= QCA808X_PMA_TYPE_100M;
break;
case FAL_SPEED_10:
phy_data1 |= QCA808X_PMA_CONTROL_10M;
phy_data2 |= QCA808X_PMA_TYPE_10M;
break;
default:
return SW_BAD_PARAM;
}
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD1_NUM,
QCA808X_PHY_MMD1_PMA_CONTROL, phy_data1);
PHY_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD1_NUM,
QCA808X_PHY_MMD1_PMA_TYPE, phy_data2);
return rv;
}
sw_error_t
_qca808x_phy_set_autoneg_adv_ext(a_uint32_t dev_id, a_uint32_t phy_id, a_uint32_t autoneg)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_AUTONEGOTIATION_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (autoneg & FAL_PHY_ADV_2500T_FD) {
phy_data |= QCA808X_ADVERTISE_2500FULL;
} else {
phy_data &= ~QCA808X_ADVERTISE_2500FULL;
}
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_AUTONEGOTIATION_CONTROL, phy_data);
return rv;
}
/******************************************************************************
*
* qca808x_phy_set_speed - Determines the speed of phy ports associated with the
* specified device.
*/
sw_error_t
qca808x_phy_set_speed(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_speed_t speed)
{
a_uint16_t phy_data = 0;
fal_port_duplex_t old_duplex = QCA808X_CTRL_FULL_DUPLEX;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
switch(speed)
{
case FAL_SPEED_2500:
case FAL_SPEED_1000:
if (speed == FAL_SPEED_2500) {
if(!qca808x_phy_2500caps(dev_id, phy_id))
return SW_NOT_SUPPORTED;
rv = _qca808x_phy_set_autoneg_adv_ext(dev_id, phy_id,
FAL_PHY_ADV_2500T_FD);
PHY_RTN_ON_ERROR(rv);
} else {
rv = _qca808x_phy_set_autoneg_adv_ext(dev_id, phy_id,
~FAL_PHY_ADV_2500T_FD);
PHY_RTN_ON_ERROR(rv);
}
phy_data |= QCA808X_CTRL_FULL_DUPLEX;
phy_data |= QCA808X_CTRL_AUTONEGOTIATION_ENABLE;
phy_data |= QCA808X_CTRL_RESTART_AUTONEGOTIATION;
break;
case FAL_SPEED_100:
case FAL_SPEED_10:
/* set qca808x phy speed by pma control registers */
rv = qca808x_phy_set_force_speed(dev_id, phy_id, speed);
PHY_RTN_ON_ERROR(rv);
rv = qca808x_phy_get_duplex(dev_id, phy_id, &old_duplex);
PHY_RTN_ON_ERROR(rv);
if (old_duplex == FAL_FULL_DUPLEX) {
phy_data |= QCA808X_CTRL_FULL_DUPLEX;
}
else if (old_duplex == FAL_HALF_DUPLEX) {
phy_data &= ~QCA808X_CTRL_FULL_DUPLEX;
}
phy_data &= ~QCA808X_CTRL_AUTONEGOTIATION_ENABLE;
break;
default:
return SW_BAD_PARAM;
}
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_CONTROL, phy_data);
return rv;
}
/******************************************************************************
*
* qca808x_phy_set_duplex - Determines the duplex of phy ports associated with the
* specified device.
*/
sw_error_t
qca808x_phy_set_duplex(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_duplex_t duplex)
{
a_uint16_t phy_data = 0;
fal_port_speed_t old_speed;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
rv = qca808x_phy_get_speed(dev_id, phy_id, &old_speed);
PHY_RTN_ON_ERROR(rv);
switch(old_speed)
{
case FAL_SPEED_2500:
case FAL_SPEED_1000:
if (duplex == FAL_FULL_DUPLEX) {
phy_data |= QCA808X_CTRL_FULL_DUPLEX;
} else {
return SW_NOT_SUPPORTED;
}
phy_data |= QCA808X_CTRL_AUTONEGOTIATION_ENABLE;
if (old_speed == FAL_SPEED_2500) {
rv = _qca808x_phy_set_autoneg_adv_ext(dev_id, phy_id,
FAL_PHY_ADV_2500T_FD);
PHY_RTN_ON_ERROR(rv);
} else {
rv = _qca808x_phy_set_autoneg_adv_ext(dev_id, phy_id,
~FAL_PHY_ADV_2500T_FD);
PHY_RTN_ON_ERROR(rv);
}
break;
case FAL_SPEED_100:
case FAL_SPEED_10:
/* force the speed */
rv = qca808x_phy_set_force_speed(dev_id, phy_id, old_speed);
PHY_RTN_ON_ERROR(rv);
phy_data &= ~QCA808X_CTRL_AUTONEGOTIATION_ENABLE;
if (duplex == FAL_FULL_DUPLEX) {
phy_data |= QCA808X_CTRL_FULL_DUPLEX;
} else {
phy_data &= ~QCA808X_CTRL_FULL_DUPLEX;
}
break;
default:
return SW_FAIL;
}
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_CONTROL, phy_data);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_duplex - Determines the duplex of phy ports associated with the
* specified device.
*/
sw_error_t
qca808x_phy_get_duplex(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_duplex_t * duplex)
{
sw_error_t rv = SW_OK;
struct port_phy_status phy_status = {0};
rv = qca808x_phy_get_status(dev_id, phy_id, &phy_status);
PHY_RTN_ON_ERROR(rv);
if (phy_status.link_status == A_TRUE) {
*duplex = phy_status.duplex;
} else {
*duplex = FAL_HALF_DUPLEX;
}
return rv;
}
/******************************************************************************
*
* qca808x_phy_reset - reset the phy
*
* reset the phy
*/
sw_error_t qca808x_phy_reset(a_uint32_t dev_id, a_uint32_t phy_id)
{
a_uint16_t phy_data;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_CONTROL,
phy_data | QCA808X_CTRL_SOFTWARE_RESET);
SW_RTN_ON_ERROR(rv);
/*the configure will lost when reset.*/
rv = qca808x_phy_ms_seed_enable(dev_id, phy_id, A_TRUE);
return rv;
}
/******************************************************************************
*
* qca808x_phy_status - test to see if the specified phy link is alive
*
* RETURNS:
* A_TRUE --> link is alive
* A_FALSE --> link is down
*/
a_bool_t qca808x_phy_get_link_status(a_uint32_t dev_id, a_uint32_t phy_id)
{
struct port_phy_status phy_status = {0};
sw_error_t rv = SW_OK;
rv = qca808x_phy_get_status(dev_id, phy_id, &phy_status);
if (rv == SW_OK) {
return phy_status.link_status;
} else {
return A_FALSE;
}
}
#ifndef IN_PORTCONTROL_MINI
/******************************************************************************
*
* qca808x_phy_cdt - cable diagnostic test
*
* cable diagnostic test
*/
static inline fal_cable_status_t _phy_cdt_status_mapping(a_uint16_t status)
{
fal_cable_status_t status_mapping = FAL_CABLE_STATUS_INVALID;
switch (status) {
case 0:
status_mapping = FAL_CABLE_STATUS_INVALID;
break;
case 1:
status_mapping = FAL_CABLE_STATUS_NORMAL;
break;
case 2:
status_mapping = FAL_CABLE_STATUS_OPENED;
break;
case 3:
status_mapping = FAL_CABLE_STATUS_SHORT;
break;
}
return status_mapping;
}
static sw_error_t qca808x_phy_cdt_start(a_uint32_t dev_id, a_uint32_t phy_id)
{
a_uint16_t status = 0;
a_uint16_t ii = 100;
sw_error_t rv = SW_OK;
/* RUN CDT */
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_CDT_CONTROL,
QCA808X_RUN_CDT | QCA808X_CABLE_LENGTH_UNIT);
PHY_RTN_ON_ERROR(rv);
do {
aos_mdelay(30);
status =
qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CDT_CONTROL);
PHY_RTN_ON_READ_ERROR(status);
}
while ((status & QCA808X_RUN_CDT) && (--ii));
if (ii == 0) {
return SW_TIMEOUT;
} else {
return SW_OK;
}
}
sw_error_t
qca808x_phy_cdt(a_uint32_t dev_id, a_uint32_t phy_id, a_uint32_t mdi_pair,
fal_cable_status_t * cable_status, a_uint32_t * cable_len)
{
a_uint16_t cable_delta_time = 0;
a_uint16_t status;
sw_error_t rv;
if ((mdi_pair >= QCA808X_MDI_PAIR_NUM)) {
return SW_BAD_PARAM;
}
rv = qca808x_phy_cdt_start(dev_id, phy_id);
if (rv != SW_OK) {
*cable_status = FAL_CABLE_STATUS_INVALID;
*cable_len = 0;
return rv;
}
/* Get cable status */
status = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_CDT_STATUS);
PHY_RTN_ON_READ_ERROR(status);
switch (mdi_pair) {
case 0:
*cable_status =
_phy_cdt_status_mapping((status >> 12) & 0x3);
cable_delta_time =
qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_CDT_DIAG_PAIR0);
PHY_RTN_ON_READ_ERROR(cable_delta_time);
break;
case 1:
*cable_status =
_phy_cdt_status_mapping((status >> 8) & 0x3);
cable_delta_time =
qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_CDT_DIAG_PAIR1);
PHY_RTN_ON_READ_ERROR(cable_delta_time);
break;
case 2:
*cable_status =
_phy_cdt_status_mapping((status >> 4) & 0x3);
cable_delta_time =
qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_CDT_DIAG_PAIR2);
PHY_RTN_ON_READ_ERROR(cable_delta_time);
break;
case 3:
*cable_status =
_phy_cdt_status_mapping(status & 0x3);
cable_delta_time =
qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_CDT_DIAG_PAIR3);
PHY_RTN_ON_READ_ERROR(cable_delta_time);
break;
}
/* the actual cable length equals to CableDeltaTime * 0.824 */
*cable_len = ((cable_delta_time & 0xff) * 824) / 1000;
return rv;
}
/******************************************************************************
*
* qca808x_phy_set_mdix -
*
* set phy mdix configuraiton
*/
sw_error_t
qca808x_phy_set_mdix(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_mdix_mode_t mode)
{
a_uint16_t phy_data;
sw_error_t rv;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_SPEC_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (mode == PHY_MDIX_AUTO) {
phy_data |= QCA808X_PHY_MDIX_AUTO;
} else if (mode == PHY_MDIX_MDIX) {
phy_data &= ~QCA808X_PHY_MDIX_AUTO;
phy_data |= QCA808X_PHY_MDIX;
} else if (mode == PHY_MDIX_MDI) {
phy_data &= ~QCA808X_PHY_MDIX_AUTO;
} else {
return SW_BAD_PARAM;
}
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_SPEC_CONTROL, phy_data);
PHY_RTN_ON_ERROR(rv);
rv = qca808x_phy_reset(dev_id, phy_id);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_mdix
*
* get phy mdix configuration
*/
sw_error_t
qca808x_phy_get_mdix(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_mdix_mode_t * mode)
{
a_uint16_t phy_data;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_SPEC_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
if ((phy_data & QCA808X_PHY_MDIX_AUTO) == QCA808X_PHY_MDIX_AUTO) {
*mode = PHY_MDIX_AUTO;
} else if ((phy_data & QCA808X_PHY_MDIX) == QCA808X_PHY_MDIX) {
*mode = PHY_MDIX_MDIX;
} else {
*mode = PHY_MDIX_MDI;
}
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_get_mdix status
*
* get phy mdix status
*/
sw_error_t
qca808x_phy_get_mdix_status(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_mdix_status_t * mode)
{
a_uint16_t phy_data;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_SPEC_STATUS);
PHY_RTN_ON_READ_ERROR(phy_data);
*mode =
(phy_data & QCA808X_PHY_MDIX_STATUS) ? PHY_MDIX_STATUS_MDIX :
PHY_MDIX_STATUS_MDI;
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_set_local_loopback
*
* set phy local loopback
*/
sw_error_t
qca808x_phy_set_local_loopback(a_uint32_t dev_id, a_uint32_t phy_id,
a_bool_t enable)
{
a_uint16_t phy_data;
fal_port_speed_t old_speed;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (enable == A_TRUE) {
/* get the link speed first, then force the corresponding
* speed to enable local loopback */
rv = qca808x_phy_get_speed(dev_id, phy_id, &old_speed);
PHY_RTN_ON_ERROR(rv);
rv = qca808x_phy_set_force_speed(dev_id, phy_id, old_speed);
PHY_RTN_ON_ERROR(rv);
phy_data &= ~QCA808X_CTRL_AUTONEGOTIATION_ENABLE;
phy_data |= QCA808X_LOCAL_LOOPBACK_ENABLE;
phy_data |= QCA808X_CTRL_FULL_DUPLEX;
} else {
phy_data = QCA808X_COMMON_CTRL;
}
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_CONTROL, phy_data);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_local_loopback
*
* get phy local loopback
*/
sw_error_t
qca808x_phy_get_local_loopback(a_uint32_t dev_id, a_uint32_t phy_id,
a_bool_t * enable)
{
a_uint16_t phy_data;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (phy_data & QCA808X_LOCAL_LOOPBACK_ENABLE) {
*enable = A_TRUE;
} else {
*enable = A_FALSE;
}
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_set_remote_loopback
*
* set phy remote loopback
*/
sw_error_t
qca808x_phy_set_remote_loopback(a_uint32_t dev_id, a_uint32_t phy_id,
a_bool_t enable)
{
a_uint16_t phy_data;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_ADDR_REMOTE_LOOPBACK_CTRL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (enable == A_TRUE) {
phy_data |= QCA808X_PHY_REMOTE_LOOPBACK_EN;
} else {
phy_data &= ~QCA808X_PHY_REMOTE_LOOPBACK_EN;
}
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_ADDR_REMOTE_LOOPBACK_CTRL,
phy_data);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_remote_loopback
*
* get phy remote loopback
*/
sw_error_t
qca808x_phy_get_remote_loopback(a_uint32_t dev_id, a_uint32_t phy_id,
a_bool_t * enable)
{
a_uint16_t phy_data;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_ADDR_REMOTE_LOOPBACK_CTRL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (phy_data & QCA808X_PHY_REMOTE_LOOPBACK_EN) {
*enable = A_TRUE;
} else {
*enable = A_FALSE;
}
return SW_OK;
}
#endif
/******************************************************************************
*
* qca808x_set_autoneg_adv - set the phy autoneg Advertisement
*
*/
sw_error_t
qca808x_phy_set_autoneg_adv(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t autoneg)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_reg_read(dev_id, phy_id,
QCA808X_AUTONEG_ADVERT);
PHY_RTN_ON_READ_ERROR(phy_data);
phy_data &= ~QCA808X_ADVERTISE_MEGA_ALL;
if (autoneg & FAL_PHY_ADV_100TX_FD) {
phy_data |= QCA808X_ADVERTISE_100FULL;
}
if (autoneg & FAL_PHY_ADV_100TX_HD) {
phy_data |= QCA808X_ADVERTISE_100HALF;
}
if (autoneg & FAL_PHY_ADV_10T_FD) {
phy_data |= QCA808X_ADVERTISE_10FULL;
}
if (autoneg & FAL_PHY_ADV_10T_HD) {
phy_data |= QCA808X_ADVERTISE_10HALF;
}
if (autoneg & FAL_PHY_ADV_PAUSE) {
phy_data |= QCA808X_ADVERTISE_PAUSE;
}
if (autoneg & FAL_PHY_ADV_ASY_PAUSE) {
phy_data |= QCA808X_ADVERTISE_ASYM_PAUSE;
}
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_AUTONEG_ADVERT,
phy_data);
PHY_RTN_ON_ERROR(rv);
phy_data = qca808x_phy_reg_read(dev_id, phy_id,
QCA808X_1000BASET_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
phy_data &= ~QCA808X_ADVERTISE_1000FULL;
phy_data &= ~QCA808X_ADVERTISE_1000HALF;
if (autoneg & FAL_PHY_ADV_1000T_FD) {
phy_data |= QCA808X_ADVERTISE_1000FULL;
}
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_1000BASET_CONTROL,
phy_data);
PHY_RTN_ON_ERROR(rv);
if (qca808x_phy_2500caps(dev_id, phy_id) == A_TRUE) {
rv = _qca808x_phy_set_autoneg_adv_ext(dev_id, phy_id, autoneg);
PHY_RTN_ON_ERROR(rv);
} else {
if(autoneg & FAL_PHY_ADV_2500T_FD) {
SSDK_ERROR("2.5G auto adv is not supported\n");
return SW_NOT_SUPPORTED;
}
}
return SW_OK;
}
sw_error_t
_qca808x_phy_get_autoneg_adv_ext(a_uint32_t dev_id, a_uint32_t phy_id, a_uint16_t *phy_data)
{
*phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_AUTONEGOTIATION_CONTROL);
PHY_RTN_ON_READ_ERROR(*phy_data);
return SW_OK;
}
/******************************************************************************
*
* qca808x_get_autoneg_adv - get the phy autoneg Advertisement
*
*/
sw_error_t
qca808x_phy_get_autoneg_adv(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t * autoneg)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
*autoneg = 0;
phy_data =
qca808x_phy_reg_read(dev_id, phy_id, QCA808X_AUTONEG_ADVERT);
PHY_RTN_ON_READ_ERROR(phy_data);
if (phy_data & QCA808X_ADVERTISE_100FULL) {
*autoneg |= FAL_PHY_ADV_100TX_FD;
}
if (phy_data & QCA808X_ADVERTISE_100HALF) {
*autoneg |= FAL_PHY_ADV_100TX_HD;
}
if (phy_data & QCA808X_ADVERTISE_10FULL) {
*autoneg |= FAL_PHY_ADV_10T_FD;
}
if (phy_data & QCA808X_ADVERTISE_10HALF) {
*autoneg |= FAL_PHY_ADV_10T_HD;
}
if (phy_data & QCA808X_ADVERTISE_PAUSE) {
*autoneg |= FAL_PHY_ADV_PAUSE;
}
if (phy_data & QCA808X_ADVERTISE_ASYM_PAUSE) {
*autoneg |= FAL_PHY_ADV_ASY_PAUSE;
}
phy_data = qca808x_phy_reg_read(dev_id, phy_id,
QCA808X_1000BASET_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (phy_data & QCA808X_ADVERTISE_1000FULL) {
*autoneg |= FAL_PHY_ADV_1000T_FD;
}
if (qca808x_phy_2500caps(dev_id, phy_id) == A_TRUE) {
rv = _qca808x_phy_get_autoneg_adv_ext(dev_id, phy_id, &phy_data);
if ((rv == SW_OK) &&
(phy_data & QCA808X_ADVERTISE_2500FULL)) {
*autoneg |= FAL_PHY_ADV_2500T_FD;
}
}
return rv;
}
/******************************************************************************
*
* qca808x_phy_autoneg_status - get the phy autoneg status
*
*/
a_bool_t qca808x_phy_autoneg_status(a_uint32_t dev_id, a_uint32_t phy_id)
{
a_uint16_t phy_data;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CONTROL);
if (phy_data & QCA808X_CTRL_AUTONEGOTIATION_ENABLE) {
return A_TRUE;
}
return A_FALSE;
}
/******************************************************************************
*
* qca808x_restart_autoneg - restart the phy autoneg
*
*/
sw_error_t qca808x_phy_restart_autoneg(a_uint32_t dev_id, a_uint32_t phy_id)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
phy_data |= QCA808X_CTRL_AUTONEGOTIATION_ENABLE;
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_CONTROL,
phy_data | QCA808X_CTRL_RESTART_AUTONEGOTIATION);
return rv;
}
/******************************************************************************
*
* qca808x_phy_enable_autonego
*
*/
sw_error_t qca808x_phy_enable_autoneg(a_uint32_t dev_id, a_uint32_t phy_id)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_CONTROL,
phy_data | QCA808X_CTRL_AUTONEGOTIATION_ENABLE);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_phy_id - get the phy id
*
*/
sw_error_t
qca808x_phy_get_phy_id(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t *phy_data)
{
a_uint16_t org_id, rev_id;
org_id = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_ID1);
PHY_RTN_ON_READ_ERROR(org_id);
rev_id = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_ID2);
PHY_RTN_ON_READ_ERROR(rev_id);
*phy_data = ((org_id & 0xffff) << 16) | (rev_id & 0xffff);
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_off - power off the phy
*
* Power off the phy
*/
sw_error_t qca808x_phy_poweroff(a_uint32_t dev_id, a_uint32_t phy_id)
{
a_uint16_t phy_data;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_CONTROL,
phy_data | QCA808X_CTRL_POWER_DOWN);
return rv;
}
/******************************************************************************
*
* qca808x_phy_on - power on the phy
*
* Power on the phy
*/
sw_error_t qca808x_phy_poweron(a_uint32_t dev_id, a_uint32_t phy_id)
{
a_uint16_t phy_data;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CONTROL);
PHY_RTN_ON_READ_ERROR(phy_data);
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_CONTROL,
phy_data & ~QCA808X_CTRL_POWER_DOWN);
aos_mdelay(200);
return rv;
}
#ifndef IN_PORTCONTROL_MINI
/******************************************************************************
*
* qca808x_phy_set_802.3az
*
* set 802.3az status
*/
sw_error_t
qca808x_phy_set_8023az(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t enable)
{
a_uint16_t phy_data;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_ADDR_8023AZ_EEE_CTRL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (enable == A_TRUE) {
phy_data |= QCA808X_PHY_8023AZ_EEE_1000BT;
phy_data |= QCA808X_PHY_8023AZ_EEE_100BT;
} else {
phy_data &= ~QCA808X_PHY_8023AZ_EEE_1000BT;
phy_data &= ~QCA808X_PHY_8023AZ_EEE_100BT;
}
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_ADDR_8023AZ_EEE_CTRL, phy_data);
PHY_RTN_ON_ERROR(rv);
rv = qca808x_phy_restart_autoneg(dev_id, phy_id);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_8023az status
*
* get 8023az status
*/
sw_error_t
qca808x_phy_get_8023az(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t * enable)
{
a_uint16_t phy_data;
*enable = A_FALSE;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_ADDR_8023AZ_EEE_CTRL);
PHY_RTN_ON_READ_ERROR(phy_data);
if ((phy_data & QCA808X_PHY_8023AZ_EEE_1000BT) &&
(phy_data & QCA808X_PHY_8023AZ_EEE_100BT)) {
*enable = A_TRUE;
}
return SW_OK;
}
/******************************************************************************
*
* _qca808x_phy_get_8023az_status status
*
* get 8023az status
*/
sw_error_t
_qca808x_phy_get_8023az_status(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t * enable)
{
a_uint16_t phy_data;
*enable = A_FALSE;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_ADDR_8023AZ_EEE_DB);
PHY_RTN_ON_READ_ERROR(phy_data);
if (phy_data & QCA808X_PHY_8023AZ_EEE_LP_STAT) {
*enable = A_TRUE;
}
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_set wol frame mac address
*
* set phy wol frame mac address
*/
sw_error_t
qca808x_phy_set_magic_frame_mac(a_uint32_t dev_id, a_uint32_t phy_id,
fal_mac_addr_t * mac)
{
a_uint16_t phy_data1;
a_uint16_t phy_data2;
a_uint16_t phy_data3;
sw_error_t rv = SW_OK;
phy_data1 = (mac->uc[0] << 8) | mac->uc[1];
phy_data2 = (mac->uc[2] << 8) | mac->uc[3];
phy_data3 = (mac->uc[4] << 8) | mac->uc[5];
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_WOL_MAGIC_MAC_CTRL1, phy_data1);
PHY_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_WOL_MAGIC_MAC_CTRL2, phy_data2);
PHY_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_WOL_MAGIC_MAC_CTRL3, phy_data3);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get wol frame mac address
*
* get phy wol frame mac address
*/
sw_error_t
qca808x_phy_get_magic_frame_mac(a_uint32_t dev_id, a_uint32_t phy_id,
fal_mac_addr_t * mac)
{
a_uint16_t phy_data1;
a_uint16_t phy_data2;
a_uint16_t phy_data3;
phy_data1 = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_WOL_MAGIC_MAC_CTRL1);
PHY_RTN_ON_READ_ERROR(phy_data1);
phy_data2 = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_WOL_MAGIC_MAC_CTRL2);
PHY_RTN_ON_READ_ERROR(phy_data2);
phy_data3 = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_WOL_MAGIC_MAC_CTRL3);
PHY_RTN_ON_READ_ERROR(phy_data3);
mac->uc[0] = (phy_data1 >> 8);
mac->uc[1] = (phy_data1 & 0x00ff);
mac->uc[2] = (phy_data2 >> 8);
mac->uc[3] = (phy_data2 & 0x00ff);
mac->uc[4] = (phy_data3 >> 8);
mac->uc[5] = (phy_data3 & 0x00ff);
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_set wol enable or disable
*
* set phy wol enable or disable
*/
sw_error_t
qca808x_phy_set_wol_status(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t enable)
{
a_uint16_t phy_data;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_WOL_CTRL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (enable == A_TRUE) {
phy_data |= QCA808X_PHY_WOL_EN;
} else {
phy_data &= ~QCA808X_PHY_WOL_EN;
}
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_WOL_CTRL, phy_data);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_wol status
*
* get wol status
*/
sw_error_t
qca808x_phy_get_wol_status(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t * enable)
{
a_uint16_t phy_data;
*enable = A_FALSE;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_WOL_CTRL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (phy_data & QCA808X_PHY_WOL_EN) {
*enable = A_TRUE;
}
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_set_hibernate - set hibernate status
*
* set hibernate status
*/
sw_error_t
qca808x_phy_set_hibernate(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t enable)
{
a_uint16_t phy_data;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_debug_read(dev_id, phy_id,
QCA808X_DEBUG_PHY_HIBERNATION_CTRL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (enable == A_TRUE) {
phy_data |= QCA808X_PHY_HIBERNATION_CFG;
} else {
phy_data &= ~QCA808X_PHY_HIBERNATION_CFG;
}
rv = qca808x_phy_debug_write(dev_id, phy_id,
QCA808X_DEBUG_PHY_HIBERNATION_CTRL, phy_data);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_hibernate - get hibernate status
*
* get hibernate status
*/
sw_error_t
qca808x_phy_get_hibernate(a_uint32_t dev_id, a_uint32_t phy_id,
a_bool_t * enable)
{
a_uint16_t phy_data;
*enable = A_FALSE;
phy_data = qca808x_phy_debug_read(dev_id, phy_id,
QCA808X_DEBUG_PHY_HIBERNATION_CTRL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (phy_data & QCA808X_PHY_HIBERNATION_CFG) {
*enable = A_TRUE;
}
return SW_OK;
}
/******************************************************************************
*
* _qca808x_phy_get_hibernate_status - get hibernate status
*
* get hibernate status
*/
sw_error_t
_qca808x_phy_get_hibernate_status(a_uint32_t dev_id, a_uint32_t phy_id,
a_bool_t * enable)
{
a_uint16_t phy_data;
*enable = A_TRUE;
phy_data = qca808x_phy_debug_read(dev_id, phy_id,
QCA808X_DEBUG_PHY_HIBERNATION_STAT);
PHY_RTN_ON_READ_ERROR(phy_data);
if (phy_data & QCA808X_PHY_HIBERNATION_STAT_EN) {
*enable = A_FALSE;
}
return SW_OK;
}
#endif
/******************************************************************************
*
* qca808x_phy_interface mode set
*
* set qca808x phy interface mode
*/
sw_error_t
qca808x_phy_interface_set_mode(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_interface_mode_t interface_mode)
{
/* qca808x phy will automatically switch the interface mode according
* to the speed, 2.5G works on SGMII+, other works on SGMII.
*/
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_interface mode get
*
* get qca808x phy interface mode
*/
sw_error_t
qca808x_phy_interface_get_mode(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_interface_mode_t *interface_mode)
{
a_uint16_t phy_data;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CHIP_CONFIG);
PHY_RTN_ON_READ_ERROR(phy_data);
phy_data &= QCA808X_PHY_CHIP_MODE_CFG;
if (phy_data == QCA808X_PHY_SGMII_BASET) {
*interface_mode = PHY_SGMII_BASET;
}
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_interface mode status get
*
* get qca808x phy interface mode status
*/
sw_error_t
qca808x_phy_interface_get_mode_status(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_interface_mode_t *interface_mode_status)
{
a_uint16_t phy_data;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_CHIP_CONFIG);
PHY_RTN_ON_READ_ERROR(phy_data);
phy_data &= QCA808X_PHY_MODE_MASK;
switch (phy_data) {
case QCA808X_PHY_SGMII_PLUS_MODE:
*interface_mode_status = PORT_SGMII_PLUS;
break;
case QCA808X_PHY_SGMII_MODE:
*interface_mode_status = PHY_SGMII_BASET;
break;
default:
*interface_mode_status = PORT_INTERFACE_MODE_MAX;
break;
}
return SW_OK;
}
#ifndef IN_PORTCONTROL_MINI
/******************************************************************************
*
* qca808x_phy_set_intr_mask - Set interrupt mask with the
* specified device.
*/
sw_error_t
qca808x_phy_set_intr_mask(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t intr_mask_flag)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_INTR_MASK);
PHY_RTN_ON_READ_ERROR(phy_data);
if (intr_mask_flag & FAL_PHY_INTR_STATUS_UP_CHANGE) {
phy_data |= QCA808X_INTR_STATUS_UP_CHANGE;
} else {
phy_data &= (~QCA808X_INTR_STATUS_UP_CHANGE);
}
if (intr_mask_flag & FAL_PHY_INTR_STATUS_DOWN_CHANGE) {
phy_data |= QCA808X_INTR_STATUS_DOWN_CHANGE;
} else {
phy_data &= (~QCA808X_INTR_STATUS_DOWN_CHANGE);
}
if (intr_mask_flag & FAL_PHY_INTR_SPEED_CHANGE) {
phy_data |= QCA808X_INTR_SPEED_CHANGE;
} else {
phy_data &= (~QCA808X_INTR_SPEED_CHANGE);
}
if (intr_mask_flag & FAL_PHY_INTR_BX_FX_STATUS_UP_CHANGE) {
phy_data |= QCA808X_INTR_LINK_SUCCESS_SG;
} else {
phy_data &= (~QCA808X_INTR_LINK_SUCCESS_SG);
}
if (intr_mask_flag & FAL_PHY_INTR_BX_FX_STATUS_DOWN_CHANGE) {
phy_data |= QCA808X_INTR_LINK_FAIL_SG;
} else {
phy_data &= (~QCA808X_INTR_LINK_FAIL_SG);
}
if (intr_mask_flag & FAL_PHY_INTR_WOL_STATUS) {
phy_data |= QCA808X_INTR_WOL;
} else {
phy_data &= (~QCA808X_INTR_WOL);
}
if (intr_mask_flag & FAL_PHY_INTR_POE_STATUS) {
phy_data |= QCA808X_INTR_POE;
} else {
phy_data &= (~QCA808X_INTR_POE);
}
rv = qca808x_phy_reg_write(dev_id, phy_id, QCA808X_PHY_INTR_MASK, phy_data);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_intr_mask - Get interrupt mask with the
* specified device.
*/
sw_error_t
qca808x_phy_get_intr_mask(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t * intr_mask_flag)
{
a_uint16_t phy_data = 0;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_INTR_MASK);
PHY_RTN_ON_READ_ERROR(phy_data);
*intr_mask_flag = 0;
if (phy_data & QCA808X_INTR_STATUS_UP_CHANGE) {
*intr_mask_flag |= FAL_PHY_INTR_STATUS_UP_CHANGE;
}
if (phy_data & QCA808X_INTR_STATUS_DOWN_CHANGE) {
*intr_mask_flag |= FAL_PHY_INTR_STATUS_DOWN_CHANGE;
}
if (phy_data & QCA808X_INTR_SPEED_CHANGE) {
*intr_mask_flag |= FAL_PHY_INTR_SPEED_CHANGE;
}
if (phy_data & QCA808X_INTR_LINK_SUCCESS_SG) {
*intr_mask_flag |= FAL_PHY_INTR_BX_FX_STATUS_UP_CHANGE;
}
if (phy_data & QCA808X_INTR_LINK_FAIL_SG) {
*intr_mask_flag |= FAL_PHY_INTR_BX_FX_STATUS_DOWN_CHANGE;
}
if (phy_data & QCA808X_INTR_WOL) {
*intr_mask_flag |= FAL_PHY_INTR_WOL_STATUS;
}
if (phy_data & QCA808X_INTR_POE) {
*intr_mask_flag |= FAL_PHY_INTR_POE_STATUS;
}
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_get_intr_status - Get interrupt status with the
* specified device.
*/
sw_error_t
qca808x_phy_get_intr_status(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t * intr_status_flag)
{
a_uint16_t phy_data = 0;
phy_data = qca808x_phy_reg_read(dev_id, phy_id, QCA808X_PHY_INTR_STATUS);
PHY_RTN_ON_READ_ERROR(phy_data);
*intr_status_flag = 0;
if (phy_data & QCA808X_INTR_STATUS_UP_CHANGE) {
*intr_status_flag |= FAL_PHY_INTR_STATUS_UP_CHANGE;
}
if (phy_data & QCA808X_INTR_STATUS_DOWN_CHANGE) {
*intr_status_flag |= FAL_PHY_INTR_STATUS_DOWN_CHANGE;
}
if (phy_data & QCA808X_INTR_SPEED_CHANGE) {
*intr_status_flag |= FAL_PHY_INTR_SPEED_CHANGE;
}
if (phy_data & QCA808X_INTR_LINK_SUCCESS_SG) {
*intr_status_flag |= FAL_PHY_INTR_BX_FX_STATUS_UP_CHANGE;
}
if (phy_data & QCA808X_INTR_LINK_FAIL_SG) {
*intr_status_flag |= FAL_PHY_INTR_BX_FX_STATUS_DOWN_CHANGE;
}
if (phy_data & QCA808X_INTR_WOL) {
*intr_status_flag |= FAL_PHY_INTR_WOL_STATUS;
}
if (phy_data & QCA808X_INTR_POE) {
*intr_status_flag |= FAL_PHY_INTR_POE_STATUS;
}
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_set_counter - set counter status
*
* set counter status
*/
sw_error_t
qca808x_phy_set_counter(a_uint32_t dev_id, a_uint32_t phy_id, a_bool_t enable)
{
a_uint16_t phy_data;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_COUNTER_CTRL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (enable == A_TRUE) {
phy_data |= QCA808X_PHY_FRAME_CHECK_EN;
phy_data |= QCA808X_PHY_XMIT_MAC_CNT_SELFCLR;
} else {
phy_data &= ~QCA808X_PHY_FRAME_CHECK_EN;
phy_data &= ~QCA808X_PHY_XMIT_MAC_CNT_SELFCLR;
}
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_COUNTER_CTRL, phy_data);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_counter_status - get counter status
*
* set counter status
*/
sw_error_t
qca808x_phy_get_counter(a_uint32_t dev_id, a_uint32_t phy_id,
a_bool_t * enable)
{
a_uint16_t phy_data;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_COUNTER_CTRL);
PHY_RTN_ON_READ_ERROR(phy_data);
if (phy_data & QCA808X_PHY_FRAME_CHECK_EN) {
*enable = A_TRUE;
} else {
*enable = A_FALSE;
}
return SW_OK;
}
/******************************************************************************
*
* qca808x_phy_show show counter statistics
*
* show counter statistics
*/
sw_error_t
qca808x_phy_show_counter(a_uint32_t dev_id, a_uint32_t phy_id,
fal_port_counter_info_t * counter_infor)
{
a_uint16_t ingress_high_counter = 0;
a_uint16_t ingress_low_counter = 0;
a_uint16_t egress_high_counter = 0;
a_uint16_t egress_low_counter = 0;
ingress_high_counter = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_INGRESS_COUNTER_HIGH);
ingress_low_counter = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_INGRESS_COUNTER_LOW);
counter_infor->RxGoodFrame = (ingress_high_counter << 16 ) | ingress_low_counter;
counter_infor->RxBadCRC = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_INGRESS_ERROR_COUNTER);
egress_high_counter = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_EGRESS_COUNTER_HIGH);
egress_low_counter = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_EGRESS_COUNTER_LOW);
counter_infor->TxGoodFrame = (egress_high_counter << 16 ) | egress_low_counter;
counter_infor->TxBadCRC = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_EGRESS_ERROR_COUNTER);
return SW_OK;
}
#endif
/******************************************************************************
*
* qca808x_phy_set_eee_advertisement
*
* set eee advertisement
*/
sw_error_t
qca808x_phy_set_eee_adv(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t adv)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_ADDR_8023AZ_EEE_CTRL);
phy_data &= ~(QCA808X_PHY_EEE_ADV_100M | QCA808X_PHY_EEE_ADV_1000M);
if (adv & FAL_PHY_EEE_100BASE_T) {
phy_data |= QCA808X_PHY_EEE_ADV_100M;
}
if (adv & FAL_PHY_EEE_1000BASE_T) {
phy_data |= QCA808X_PHY_EEE_ADV_1000M;
}
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_ADDR_8023AZ_EEE_CTRL, phy_data);
rv = qca808x_phy_restart_autoneg(dev_id, phy_id);
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_eee_advertisement
*
* get eee advertisement
*/
sw_error_t
qca808x_phy_get_eee_adv(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t *adv)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
*adv = 0;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_ADDR_8023AZ_EEE_CTRL);
if (phy_data & QCA808X_PHY_EEE_ADV_100M) {
*adv |= FAL_PHY_EEE_100BASE_T;
}
if (phy_data & QCA808X_PHY_EEE_ADV_1000M) {
*adv |= FAL_PHY_EEE_1000BASE_T;
}
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_eee_partner_advertisement
*
* get eee partner advertisement
*/
sw_error_t
qca808x_phy_get_eee_partner_adv(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t *adv)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
*adv = 0;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_ADDR_8023AZ_EEE_PARTNER);
if (phy_data & QCA808X_PHY_EEE_PARTNER_ADV_100M) {
*adv |= FAL_PHY_EEE_100BASE_T;
}
if (phy_data & QCA808X_PHY_EEE_PARTNER_ADV_1000M) {
*adv |= FAL_PHY_EEE_1000BASE_T;
}
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_eee_capability
*
* get eee capability
*/
sw_error_t
qca808x_phy_get_eee_cap(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t *cap)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
*cap = 0;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_ADDR_8023AZ_EEE_CAPABILITY);
if (phy_data & QCA808X_PHY_EEE_CAPABILITY_100M) {
*cap |= FAL_PHY_EEE_100BASE_T;
}
if (phy_data & QCA808X_PHY_EEE_CAPABILITY_1000M) {
*cap |= FAL_PHY_EEE_1000BASE_T;
}
return rv;
}
/******************************************************************************
*
* qca808x_phy_get_eee_status
*
* get eee status
*/
sw_error_t
qca808x_phy_get_eee_status(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t *status)
{
a_uint16_t phy_data = 0;
sw_error_t rv = SW_OK;
*status = 0;
phy_data = qca808x_phy_mmd_read(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_ADDR_8023AZ_EEE_STATUS);
if (phy_data & QCA808X_PHY_EEE_STATUS_100M) {
*status |= FAL_PHY_EEE_100BASE_T;
}
if (phy_data & QCA808X_PHY_EEE_STATUS_1000M) {
*status |= FAL_PHY_EEE_1000BASE_T;
}
return rv;
}
/******************************************************************************
*
* qca808x_phy_led_init - set led behavior
*
* set led behavior
*/
static sw_error_t
qca808x_phy_led_init(a_uint32_t dev_id, a_uint32_t phy_id)
{
sw_error_t rv = SW_OK;
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_LED_POLARITY_CTRL,
QCA808X_PHY_MMD7_LED_POLARITY_ACTIVE_HIGH);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_LED0_CTRL,
QCA808X_PHY_MMD7_LED0_CTRL_ENABLE);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_LED1_CTRL,
QCA808X_PHY_MMD7_LED1_CTRL_DISABLE);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_LED2_CTRL,
QCA808X_PHY_MMD7_LED2_CTRL_DISABLE);
SW_RTN_ON_ERROR(rv);
return rv;
}
static sw_error_t
qca808x_phy_fast_retrain_cfg(a_uint32_t dev_id, a_uint32_t phy_id)
{
sw_error_t rv = SW_OK;
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_AUTONEGOTIATION_CONTROL,
QCA808X_ADVERTISE_2500FULL |
QCA808X_PHY_FAST_RETRAIN_2500BT |
QCA808X_PHY_ADV_LOOP_TIMING);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD1_NUM,
QCA808X_PHY_MMD1_FAST_RETRAIN_STATUS_CTL,
QCA808X_PHY_FAST_RETRAIN_CTRL);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD1_NUM,
QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,
QCA808X_PHY_MSE_THRESHOLD_20DB_VALUE);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD1_NUM,
QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,
QCA808X_PHY_MSE_THRESHOLD_17DB_VALUE);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD1_NUM,
QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,
QCA808X_PHY_MSE_THRESHOLD_27DB_VALUE);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD1_NUM,
QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,
QCA808X_PHY_MSE_THRESHOLD_28DB_VALUE);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_ADDR_EEE_LP_ADVERTISEMENT,
QCA808X_PHY_EEE_ADV_THP);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD7_NUM,
QCA808X_PHY_MMD7_TOP_OPTION1,
QCA808X_PHY_TOP_OPTION1_DATA);
SW_RTN_ON_ERROR(rv);
/*adjust the threshold for link down*/
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
0xa100, 0x9203);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
0xa105, 0x8001);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
0xa106, 0x1111);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
0xa103, 0x1698);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
0xa011, 0x5f85);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_mmd_write(dev_id, phy_id, QCA808X_PHY_MMD3_NUM,
0xa101, 0x48ad);
return rv;
}
void qca808x_phy_lock_init(void)
{
static a_bool_t is_init = A_FALSE;
if(!is_init)
{
QCA808X_LOCKER_INIT;
is_init = A_TRUE;
}
return;
}
static sw_error_t
qca808x_phy_adc_threshold_set(a_uint32_t dev_id, a_uint32_t phy_id,
a_uint32_t adc_thresold)
{
sw_error_t rv = SW_OK;
a_uint16_t phy_data = 0;
phy_data = qca808x_phy_debug_read(dev_id, phy_id,
QCA808X_PHY_ADC_THRESHOLD);
PHY_RTN_ON_READ_ERROR(phy_data);
phy_data &= ~(BITS(0, 8));
rv = qca808x_phy_debug_write (dev_id, phy_id,
QCA808X_PHY_ADC_THRESHOLD, phy_data | adc_thresold);
return rv;
}
static sw_error_t
qca808x_phy_hw_init(a_uint32_t dev_id, a_uint32_t port_bmp)
{
a_uint16_t phy_data = 0;
a_uint32_t port_id = 0, phy_addr = 0;
sw_error_t rv = SW_OK;
for (port_id = SSDK_PHYSICAL_PORT0; port_id < SW_MAX_NR_PORT; port_id ++)
{
if (port_bmp & (0x1 << port_id))
{
phy_addr = qca_ssdk_port_to_phy_addr(dev_id, port_id);
/*enable vga when init napa to fix 8023az issue*/
phy_data = qca808x_phy_mmd_read(dev_id, phy_addr, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_ADDR_CLD_CTRL7);
phy_data &= (~QCA808X_PHY_8023AZ_AFE_CTRL_MASK);
phy_data |= QCA808X_PHY_8023AZ_AFE_EN;
rv = qca808x_phy_mmd_write(dev_id, phy_addr, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_ADDR_CLD_CTRL7, phy_data);
SW_RTN_ON_ERROR(rv);
/*set napa led pin behavior on HK board*/
rv = qca808x_phy_led_init(dev_id, phy_addr);
SW_RTN_ON_ERROR(rv);
/*special configuration for AZ under 1G speed mode*/
phy_data = QCA808X_PHY_MMD3_AZ_TRAINING_VAL;
rv = qca808x_phy_mmd_write(dev_id, phy_addr, QCA808X_PHY_MMD3_NUM,
QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, phy_data);
SW_RTN_ON_ERROR(rv);
if(qca808x_phy_2500caps(dev_id, phy_addr) == A_TRUE)
{
/*config the fast retrain*/
rv = qca808x_phy_fast_retrain_cfg(dev_id, phy_addr);
SW_RTN_ON_ERROR(rv);
/*enable seed and configure ramdom seed in order that napa can be
as slave easier*/
rv = qca808x_phy_ms_seed_enable(dev_id, phy_addr, A_TRUE);
SW_RTN_ON_ERROR(rv);
rv = qca808x_phy_ms_random_seed_set(dev_id, phy_addr);
SW_RTN_ON_ERROR(rv);
}
/*set adc threshold as 100mv for 10M*/
rv = qca808x_phy_adc_threshold_set(dev_id, phy_addr,
QCA808X_PHY_ADC_THRESHOLD_100MV);
SW_RTN_ON_ERROR(rv);
}
}
return rv;
}
static sw_error_t qca808x_phy_api_ops_init(void)
{
sw_error_t ret = SW_OK;
hsl_phy_ops_t *qca808x_phy_api_ops = NULL;
qca808x_phy_api_ops = kzalloc(sizeof(hsl_phy_ops_t), GFP_KERNEL);
if (qca808x_phy_api_ops == NULL) {
SSDK_ERROR("qca808x phy ops kzalloc failed!\n");
return -ENOMEM;
}
phy_api_ops_init(QCA808X_PHY_CHIP);
qca808x_phy_api_ops->phy_reg_write = qca808x_phy_reg_write;
qca808x_phy_api_ops->phy_reg_read = qca808x_phy_reg_read;
qca808x_phy_api_ops->phy_debug_write = qca808x_phy_debug_write;
qca808x_phy_api_ops->phy_debug_read = qca808x_phy_debug_read;
qca808x_phy_api_ops->phy_mmd_write = qca808x_phy_mmd_write;
qca808x_phy_api_ops->phy_mmd_read = qca808x_phy_mmd_read;
qca808x_phy_api_ops->phy_get_status = qca808x_phy_get_status;
qca808x_phy_api_ops->phy_speed_get = qca808x_phy_get_speed;
qca808x_phy_api_ops->phy_speed_set = qca808x_phy_set_speed;
qca808x_phy_api_ops->phy_duplex_get = qca808x_phy_get_duplex;
qca808x_phy_api_ops->phy_duplex_set = qca808x_phy_set_duplex;
qca808x_phy_api_ops->phy_autoneg_enable_set = qca808x_phy_enable_autoneg;
qca808x_phy_api_ops->phy_restart_autoneg = qca808x_phy_restart_autoneg;
qca808x_phy_api_ops->phy_autoneg_status_get = qca808x_phy_autoneg_status;
qca808x_phy_api_ops->phy_autoneg_adv_set = qca808x_phy_set_autoneg_adv;
qca808x_phy_api_ops->phy_autoneg_adv_get = qca808x_phy_get_autoneg_adv;
qca808x_phy_api_ops->phy_link_status_get = qca808x_phy_get_link_status;
qca808x_phy_api_ops->phy_reset = qca808x_phy_reset;
#ifndef IN_PORTCONTROL_MINI
qca808x_phy_api_ops->phy_cdt = qca808x_phy_cdt;
qca808x_phy_api_ops->phy_mdix_set = qca808x_phy_set_mdix;
qca808x_phy_api_ops->phy_mdix_get = qca808x_phy_get_mdix;
qca808x_phy_api_ops->phy_mdix_status_get = qca808x_phy_get_mdix_status;
qca808x_phy_api_ops->phy_local_loopback_set = qca808x_phy_set_local_loopback;
qca808x_phy_api_ops->phy_local_loopback_get = qca808x_phy_get_local_loopback;
qca808x_phy_api_ops->phy_remote_loopback_set = qca808x_phy_set_remote_loopback;
qca808x_phy_api_ops->phy_remote_loopback_get = qca808x_phy_get_remote_loopback;
#endif
qca808x_phy_api_ops->phy_id_get = qca808x_phy_get_phy_id;
qca808x_phy_api_ops->phy_power_off = qca808x_phy_poweroff;
qca808x_phy_api_ops->phy_power_on = qca808x_phy_poweron;
#ifndef IN_PORTCONTROL_MINI
qca808x_phy_api_ops->phy_8023az_set = qca808x_phy_set_8023az;
qca808x_phy_api_ops->phy_8023az_get = qca808x_phy_get_8023az;
qca808x_phy_api_ops->phy_hibernation_set = qca808x_phy_set_hibernate;
qca808x_phy_api_ops->phy_hibernation_get = qca808x_phy_get_hibernate;
qca808x_phy_api_ops->phy_magic_frame_mac_set = qca808x_phy_set_magic_frame_mac;
qca808x_phy_api_ops->phy_magic_frame_mac_get = qca808x_phy_get_magic_frame_mac;
qca808x_phy_api_ops->phy_wol_status_set = qca808x_phy_set_wol_status;
qca808x_phy_api_ops->phy_wol_status_get = qca808x_phy_get_wol_status;
#endif
qca808x_phy_api_ops->phy_interface_mode_set = qca808x_phy_interface_set_mode;
qca808x_phy_api_ops->phy_interface_mode_get = qca808x_phy_interface_get_mode;
qca808x_phy_api_ops->phy_interface_mode_status_get = qca808x_phy_interface_get_mode_status;
#ifndef IN_PORTCONTROL_MINI
qca808x_phy_api_ops->phy_intr_mask_set = qca808x_phy_set_intr_mask;
qca808x_phy_api_ops->phy_intr_mask_get = qca808x_phy_get_intr_mask;
qca808x_phy_api_ops->phy_intr_status_get = qca808x_phy_get_intr_status;
qca808x_phy_api_ops->phy_counter_set = qca808x_phy_set_counter;
qca808x_phy_api_ops->phy_counter_get = qca808x_phy_get_counter;
qca808x_phy_api_ops->phy_counter_show = qca808x_phy_show_counter;
#endif
qca808x_phy_api_ops->phy_eee_adv_set = qca808x_phy_set_eee_adv;
qca808x_phy_api_ops->phy_eee_adv_get = qca808x_phy_get_eee_adv;
qca808x_phy_api_ops->phy_eee_partner_adv_get = qca808x_phy_get_eee_partner_adv;
qca808x_phy_api_ops->phy_eee_cap_get = qca808x_phy_get_eee_cap;
qca808x_phy_api_ops->phy_eee_status_get = qca808x_phy_get_eee_status;
#ifdef IN_LED
qca808x_phy_led_api_ops_init(qca808x_phy_api_ops);
#endif
/*qca808x_end*/
#if defined(IN_PTP)
qca808x_phy_ptp_api_ops_init(&qca808x_phy_api_ops->phy_ptp_ops);
#endif
/*qca808x_start*/
ret = hsl_phy_api_ops_register(QCA808X_PHY_CHIP, qca808x_phy_api_ops);
if (ret == SW_OK) {
SSDK_INFO("qca probe qca808x phy driver succeeded!\n");
} else {
SSDK_ERROR("qca probe qca808x phy driver failed! (code: %d)\n", ret);
}
return ret;
}
/******************************************************************************
*
* qca808x_phy_init -
*
*/
int qca808x_phy_init(a_uint32_t dev_id, a_uint32_t port_bmp)
{
/*qca808x_end*/
a_uint32_t port_id = 0;
/*qca808x_start*/
a_int32_t ret = 0;
if(phy_ops_flag == A_FALSE &&
qca808x_phy_api_ops_init() == SW_OK) {
qca808x_phy_lock_init();
phy_ops_flag = A_TRUE;
}
qca808x_phy_hw_init(dev_id, port_bmp);
/*qca808x_end*/
if(phy_dev_drv_init_flag == A_FALSE)
{
for (port_id = 0; port_id < SW_MAX_NR_PORT; port_id ++)
{
if (port_bmp & (0x1 << port_id)) {
qca808x_phydev_init(dev_id, port_id);
}
}
ret = qca808x_phy_driver_register();
phy_dev_drv_init_flag = A_TRUE;
}
/*qca808x_start*/
return ret;
}
void qca808x_phy_exit(a_uint32_t dev_id, a_uint32_t port_bmp)
{
/*qca808x_end*/
a_uint32_t port_id = 0;
qca808x_phy_driver_unregister();
for (port_id = 0; port_id < SW_MAX_NR_PORT; port_id ++)
{
if (port_bmp & (0x1 << port_id)) {
qca808x_phydev_deinit(dev_id, port_id);
}
}
/*qca808x_start*/
}
/*qca808x_end*/