qca: ipq40xx: Add qca8075 switch support

Change-Id: I39fdbd864e9eb8e06bd9493eb1af1dcd48485635
Signed-off-by: Balamurugan Selvarajan <bselvara@codeaurora.org>
This commit is contained in:
Balamurugan Selvarajan 2016-03-21 20:32:50 +05:30 committed by Akila N
parent f80519be25
commit 27d0f93300
2 changed files with 1252 additions and 0 deletions

View file

@ -0,0 +1,772 @@
/*
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
* 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
* GNU General Public License for more details.
*/
#include <common.h>
#include <net.h>
#include <asm-generic/errno.h>
#include <asm/io.h>
#include <asm/arch-ipq40xx/ess/ipq40xx_edma.h>
#include <malloc.h>
#include "ipq40xx_edma_eth.h"
#include "ipq40xx_qca8075.h"
extern int ipq40xx_mdio_write(int mii_id,
int regnum, u16 value);
extern int ipq40xx_mdio_read(int mii_id,
int regnum, ushort *data);
static u32 qca8075_id;
static u16 qca8075_phy_reg_write(u32 dev_id, u32 phy_id,
u32 reg_id, u16 reg_val)
{
ipq40xx_mdio_write(phy_id, reg_id, reg_val);
return 0;
}
u16 qca8075_phy_reg_read(u32 dev_id, u32 phy_id, u32 reg_id)
{
return ipq40xx_mdio_read(phy_id, reg_id, NULL);
}
/*
* phy4 prfer medium
* get phy4 prefer medum, fiber or copper;
*/
static qca8075_phy_medium_t __phy_prefer_medium_get(u32 dev_id,
u32 phy_id)
{
u16 phy_medium;
phy_medium =
qca8075_phy_reg_read(dev_id, phy_id,
QCA8075_PHY_CHIP_CONFIG);
return ((phy_medium & QCA8075_PHY4_PREFER_FIBER) ?
QCA8075_PHY_MEDIUM_FIBER : QCA8075_PHY_MEDIUM_COPPER);
}
/*
* phy4 activer medium
* get phy4 current active medium, fiber or copper;
*/
static qca8075_phy_medium_t __phy_active_medium_get(u32 dev_id,
u32 phy_id)
{
u16 phy_data = 0;
u32 phy_mode;
phy_mode = qca8075_phy_reg_read(dev_id, phy_id,
QCA8075_PHY_CHIP_CONFIG);
phy_mode &= 0x000f;
if (phy_mode == QCA8075_PHY_PSGMII_AMDET) {
phy_data = qca8075_phy_reg_read(dev_id,
phy_id, QCA8075_PHY_SGMII_STATUS);
if ((phy_data & QCA8075_PHY4_AUTO_COPPER_SELECT)) {
return QCA8075_PHY_MEDIUM_COPPER;
} else if ((phy_data & QCA8075_PHY4_AUTO_BX1000_SELECT)) {
/* PHY_MEDIUM_FIBER_BX1000 */
return QCA8075_PHY_MEDIUM_FIBER;
} else if ((phy_data & QCA8075_PHY4_AUTO_FX100_SELECT)) {
/* PHY_MEDIUM_FIBER_FX100 */
return QCA8075_PHY_MEDIUM_FIBER;
}
/* link down */
return __phy_prefer_medium_get(dev_id, phy_id);
} else if ((phy_mode == QCA8075_PHY_PSGMII_BASET) ||
(phy_mode == QCA8075_PHY_SGMII_BASET)) {
return QCA8075_PHY_MEDIUM_COPPER;
} else if ((phy_mode == QCA8075_PHY_PSGMII_BX1000) ||
(phy_mode == QCA8075_PHY_PSGMII_FX100)) {
return QCA8075_PHY_MEDIUM_FIBER;
} else {
return QCA8075_PHY_MEDIUM_COPPER;
}
}
/*
* phy4 copper page or fiber page select
* set phy4 copper or fiber page
*/
static u8 __phy_reg_pages_sel(u32 dev_id, u32 phy_id,
qca8075_phy_reg_pages_t phy_reg_pages)
{
u16 reg_pages;
reg_pages = qca8075_phy_reg_read(dev_id,
phy_id, QCA8075_PHY_CHIP_CONFIG);
if (phy_reg_pages == QCA8075_PHY_COPPER_PAGES) {
reg_pages |= 0x8000;
} else if (phy_reg_pages == QCA8075_PHY_SGBX_PAGES) {
reg_pages &= ~0x8000;
} else
return -EINVAL;
qca8075_phy_reg_write(dev_id, phy_id,
QCA8075_PHY_CHIP_CONFIG, reg_pages);
return 0;
}
/*
* phy4 reg pages selection by active medium
* phy4 reg pages selection
*/
static u32 __phy_reg_pages_sel_by_active_medium(u32 dev_id,
u32 phy_id)
{
qca8075_phy_medium_t phy_medium;
qca8075_phy_reg_pages_t reg_pages;
phy_medium = __phy_active_medium_get(dev_id, phy_id);
if (phy_medium == QCA8075_PHY_MEDIUM_FIBER) {
reg_pages = QCA8075_PHY_SGBX_PAGES;
} else if (phy_medium == QCA8075_PHY_MEDIUM_COPPER) {
reg_pages = QCA8075_PHY_COPPER_PAGES;
} else {
return -1;
}
return __phy_reg_pages_sel(dev_id, phy_id, reg_pages);
}
u8 qca8075_phy_get_link_status(u32 dev_id, u32 phy_id)
{
u16 phy_data;
if (phy_id == COMBO_PHY_ID)
__phy_reg_pages_sel_by_active_medium(dev_id, phy_id);
phy_data = qca8075_phy_reg_read(dev_id,
phy_id, QCA8075_PHY_SPEC_STATUS);
if (phy_data & QCA8075_STATUS_LINK_PASS)
return 0;
return 1;
}
u32 qca8075_phy_get_duplex(u32 dev_id, u32 phy_id,
fal_port_duplex_t * duplex)
{
u16 phy_data;
if (phy_id == COMBO_PHY_ID) {
__phy_reg_pages_sel_by_active_medium(dev_id, phy_id);
}
phy_data = qca8075_phy_reg_read(dev_id, phy_id,
QCA8075_PHY_SPEC_STATUS);
/*
* Read duplex
*/
if (phy_data & QCA8075_STATUS_FULL_DUPLEX)
*duplex = FAL_FULL_DUPLEX;
else
*duplex = FAL_HALF_DUPLEX;
return 0;
}
u32 qca8075_phy_get_speed(u32 dev_id, u32 phy_id,
fal_port_speed_t * speed)
{
u16 phy_data;
if (phy_id == COMBO_PHY_ID) {
__phy_reg_pages_sel_by_active_medium(dev_id, phy_id);
}
phy_data = qca8075_phy_reg_read(dev_id,
phy_id, QCA8075_PHY_SPEC_STATUS);
switch (phy_data & QCA8075_STATUS_SPEED_MASK) {
case QCA8075_STATUS_SPEED_1000MBS:
*speed = FAL_SPEED_1000;
break;
case QCA8075_STATUS_SPEED_100MBS:
*speed = FAL_SPEED_100;
break;
case QCA8075_STATUS_SPEED_10MBS:
*speed = FAL_SPEED_10;
break;
default:
return -EINVAL;
}
return 0;
}
static u32 qca8075_phy_mmd_write(u32 dev_id, u32 phy_id,
u16 mmd_num, u16 reg_id, u16 reg_val)
{
qca8075_phy_reg_write(dev_id, phy_id,
QCA8075_MMD_CTRL_REG, mmd_num);
qca8075_phy_reg_write(dev_id, phy_id,
QCA8075_MMD_DATA_REG, reg_id);
qca8075_phy_reg_write(dev_id, phy_id,
QCA8075_MMD_CTRL_REG,
0x4000 | mmd_num);
qca8075_phy_reg_write(dev_id, phy_id,
QCA8075_MMD_DATA_REG, reg_val);
return 0;
}
static u16 qca8075_phy_mmd_read(u32 dev_id, u32 phy_id,
u16 mmd_num, u16 reg_id)
{
qca8075_phy_reg_write(dev_id, phy_id,
QCA8075_MMD_CTRL_REG, mmd_num);
qca8075_phy_reg_write(dev_id, phy_id,
QCA8075_MMD_DATA_REG, reg_id);
qca8075_phy_reg_write(dev_id, phy_id,
QCA8075_MMD_CTRL_REG,
0x4000 | mmd_num);
return qca8075_phy_reg_read(dev_id, phy_id,
QCA8075_MMD_DATA_REG);
}
/*
* get phy4 medium is 100fx
*/
static u8 __medium_is_fiber_100fx(u32 dev_id, u32 phy_id)
{
u16 phy_data;
phy_data = qca8075_phy_reg_read(dev_id, phy_id,
QCA8075_PHY_SGMII_STATUS);
if (phy_data & QCA8075_PHY4_AUTO_FX100_SELECT) {
return 1;
}
/* Link down */
if ((!(phy_data & QCA8075_PHY4_AUTO_COPPER_SELECT)) &&
(!(phy_data & QCA8075_PHY4_AUTO_BX1000_SELECT)) &&
(!(phy_data & QCA8075_PHY4_AUTO_SGMII_SELECT))) {
phy_data = qca8075_phy_reg_read(dev_id, phy_id,
QCA8075_PHY_CHIP_CONFIG);
if ((phy_data & QCA8075_PHY4_PREFER_FIBER)
&& (!(phy_data & QCA8075_PHY4_FIBER_MODE_1000BX))) {
return 1;
}
}
return 0;
}
/*
* qca8075_phy_set_hibernate - set hibernate status
* set hibernate status
*/
static u32 qca8075_phy_set_hibernate(u32 dev_id, u32 phy_id, u8 enable)
{
u16 phy_data;
qca8075_phy_reg_write(dev_id, phy_id, QCA8075_DEBUG_PORT_ADDRESS,
QCA8075_DEBUG_PHY_HIBERNATION_CTRL);
phy_data = qca8075_phy_reg_read(dev_id, phy_id,
QCA8075_DEBUG_PORT_DATA);
if (enable) {
phy_data |= 0x8000;
} else {
phy_data &= ~0x8000;
}
qca8075_phy_reg_write(dev_id, phy_id, QCA8075_DEBUG_PORT_DATA, phy_data);
return 0;
}
/*
* qca8075_restart_autoneg - restart the phy autoneg
*/
static u32 qca8075_phy_restart_autoneg(u32 dev_id, u32 phy_id)
{
u16 phy_data;
if (phy_id == COMBO_PHY_ID) {
if (__medium_is_fiber_100fx(dev_id, phy_id))
return -1;
__phy_reg_pages_sel_by_active_medium(dev_id, phy_id);
}
phy_data = qca8075_phy_reg_read(dev_id, phy_id, QCA8075_PHY_CONTROL);
phy_data |= QCA8075_CTRL_AUTONEGOTIATION_ENABLE;
qca8075_phy_reg_write(dev_id, phy_id, QCA8075_PHY_CONTROL,
phy_data | QCA8075_CTRL_RESTART_AUTONEGOTIATION);
return 0;
}
/*
* qca8075_phy_get_8023az status
* get 8023az status
*/
static u32 qca8075_phy_get_8023az(u32 dev_id, u32 phy_id, u8 *enable)
{
u16 phy_data;
if (phy_id == COMBO_PHY_ID) {
if (QCA8075_PHY_MEDIUM_COPPER !=
__phy_active_medium_get(dev_id, phy_id))
return -1;
}
*enable = 0;
phy_data = qca8075_phy_mmd_read(dev_id, phy_id, QCA8075_PHY_MMD7_NUM,
QCA8075_PHY_MMD7_ADDR_8023AZ_EEE_CTRL);
if ((phy_data & 0x0004) && (phy_data & 0x0002))
*enable = 1;
return 0;
}
/*
* qca8075_phy_set_powersave - set power saving status
*/
static u32 qca8075_phy_set_powersave(u32 dev_id, u32 phy_id, u8 enable)
{
u16 phy_data;
u8 status = 0;
if (phy_id == COMBO_PHY_ID) {
if (QCA8075_PHY_MEDIUM_COPPER !=
__phy_active_medium_get(dev_id, phy_id))
return -1;
}
if (enable) {
qca8075_phy_get_8023az(dev_id, phy_id, &status);
if (!status) {
phy_data = qca8075_phy_mmd_read(dev_id, phy_id,
QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_8023AZ_TIMER_CTRL);
phy_data &= ~(1 << 14);
qca8075_phy_mmd_write(dev_id, phy_id,
QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_8023AZ_TIMER_CTRL,
phy_data);
}
phy_data = qca8075_phy_mmd_read(dev_id, phy_id,
QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_CLD_CTRL5);
phy_data &= ~(1 << 14);
qca8075_phy_mmd_write(dev_id, phy_id, QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_CLD_CTRL5,
phy_data);
phy_data = qca8075_phy_mmd_read(dev_id, phy_id,
QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_CLD_CTRL3);
phy_data &= ~(1 << 15);
qca8075_phy_mmd_write(dev_id, phy_id, QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_CLD_CTRL3, phy_data);
} else {
phy_data = qca8075_phy_mmd_read(dev_id, phy_id,
QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_8023AZ_TIMER_CTRL);
phy_data |= (1 << 14);
qca8075_phy_mmd_write(dev_id, phy_id, QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_8023AZ_TIMER_CTRL,
phy_data);
phy_data = qca8075_phy_mmd_read(dev_id, phy_id,
QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_CLD_CTRL5);
phy_data |= (1 << 14);
qca8075_phy_mmd_write(dev_id, phy_id, QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_CLD_CTRL5, phy_data);
phy_data = qca8075_phy_mmd_read(dev_id, phy_id,
QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_CLD_CTRL3);
phy_data |= (1 << 15);
qca8075_phy_mmd_write(dev_id, phy_id, QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_CLD_CTRL3, phy_data);
}
qca8075_phy_reg_write(dev_id, phy_id, QCA8075_PHY_CONTROL, 0x9040);
return 0;
}
/*
* qca8075_phy_set_802.3az
*/
static u32 qca8075_phy_set_8023az(u32 dev_id, u32 phy_id, u8 enable)
{
u16 phy_data;
if (phy_id == COMBO_PHY_ID) {
if (QCA8075_PHY_MEDIUM_COPPER !=
__phy_active_medium_get(dev_id, phy_id))
return -1;
}
phy_data = qca8075_phy_mmd_read(dev_id, phy_id, QCA8075_PHY_MMD7_NUM,
QCA8075_PHY_MMD7_ADDR_8023AZ_EEE_CTRL);
if (enable) {
phy_data |= 0x0006;
qca8075_phy_mmd_write(dev_id, phy_id, QCA8075_PHY_MMD7_NUM,
QCA8075_PHY_MMD7_ADDR_8023AZ_EEE_CTRL, phy_data);
if (qca8075_id == QCA8075_PHY_V1_0_5P) {
/*
* Workaround to avoid packet loss and < 10m cable
* 1000M link not stable under az enable
*/
qca8075_phy_mmd_write(dev_id, phy_id,
QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_8023AZ_TIMER_CTRL,
AZ_TIMER_CTRL_ADJUST_VALUE);
qca8075_phy_mmd_write(dev_id, phy_id,
QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_8023AZ_CLD_CTRL,
AZ_CLD_CTRL_ADJUST_VALUE);
}
} else {
phy_data &= ~0x0006;
qca8075_phy_mmd_write(dev_id, phy_id, QCA8075_PHY_MMD7_NUM,
QCA8075_PHY_MMD7_ADDR_8023AZ_EEE_CTRL, phy_data);
if (qca8075_id == QCA8075_PHY_V1_0_5P) {
qca8075_phy_mmd_write(dev_id, phy_id,
QCA8075_PHY_MMD3_NUM,
QCA8075_PHY_MMD3_ADDR_8023AZ_TIMER_CTRL,
AZ_TIMER_CTRL_DEFAULT_VALUE);
}
}
qca8075_phy_restart_autoneg(dev_id, phy_id);
return 0;
}
void ess_reset(void)
{
writel(0x1, 0x1812008);
mdelay(10);
writel(0x0, 0x1812008);
mdelay(100);
}
void qca8075_ess_reset(void)
{
int i;
u32 status;
/*
* Fix phy psgmii RX 20bit
*/
qca8075_phy_reg_write(0, 5, 0x0, 0x005b);
/*
* Reset phy psgmii
*/
qca8075_phy_reg_write(0, 5, 0x0, 0x001b);
/*
* Release reset phy psgmii
*/
qca8075_phy_reg_write(0, 5, 0x0, 0x005b);
for (i = 0; i < QCA8075_MAX_TRIES; i++) {
status = qca8075_phy_mmd_read(0, 5, 1, 0x28);
if(status & 0x1)
break;
mdelay(10);
}
if (i >= QCA8075_MAX_TRIES)
printf("qca8075 PSGMII PLL_VCO_CALIB Not Ready\n");
mdelay(50);
/*
* Check qca8075 psgmii calibration done end.
* Freeze phy psgmii RX CDR
*/
qca8075_phy_reg_write(0, 5, 0x1a, 0x2230);
ess_reset();
/*
* Check ipq40xx psgmii calibration done start
*/
for (i = 0; i < QCA8075_MAX_TRIES; i++) {
status = readl(0x000980A0);
if (status & 0x1)
break;
mdelay(10);
}
if (i >= QCA8075_MAX_TRIES)
printf("PSGMII PLL_VCO_CALIB Not Ready\n");
mdelay(50);
/*
* Check ipq40xx psgmii calibration done end.
* Relesae phy psgmii RX CDR
*/
qca8075_phy_reg_write(0, 5, 0x1a, 0x3230);
/*
* Release phy psgmii RX 20bit
*/
qca8075_phy_reg_write(0, 5, 0x0, 0x005f);
mdelay(200);
}
void psgmii_self_test(void)
{
int i, phy, j;
u32 value;
u32 phy_t_status;
u16 status;
u32 tx_counter_ok, tx_counter_error;
u32 rx_counter_ok, rx_counter_error;
u32 tx_counter_ok_high16;
u32 rx_counter_ok_high16;
u32 tx_ok, rx_ok;
/*
* Switch to access MII reg for copper
*/
qca8075_phy_reg_write(0, 4, 0x1f, 0x8500);
for (phy = 0; phy < 5; phy++) {
/*
* Enable phy mdio broadcast write
*/
qca8075_phy_mmd_write(0, phy, 7, 0x8028, 0x801f);
}
/*
* Force no link by power down
*/
qca8075_phy_reg_write(0, 0x1f, 0x0, 0x1840);
/*
* Packet number
*/
qca8075_phy_mmd_write(0, 0x1f, 7, 0x8021, 0x3000);
qca8075_phy_mmd_write(0, 0x1f, 7, 0x8062, 0x05e0);
/*
* Fix mdi status
*/
qca8075_phy_reg_write(0, 0x1f, 0x10, 0x6800);
for (i = 0; i < 100; i++) {
phy_t_status = 0;
for (phy = 0; phy < 5; phy++) {
value = readl(0xc00066c + (phy * 0xc));
/*
* Enable mac loop back
*/
writel((value | (1 << 21)), (0xc00066c + (phy * 0xc)));
}
/*
* Phy single test
*/
for (phy = 0; phy < 5; phy++) {
/*
* Enable loopback
*/
qca8075_phy_reg_write(0, phy, 0x0, 0x9000);
qca8075_phy_reg_write(0, phy, 0x0, 0x4140);
/*
* Check link
*/
j = 0;
while (j < 100) {
status = qca8075_phy_reg_read(0, phy, 0x11);
if (status & (1 << 10))
break;
mdelay(10);
j++;
}
/*
* Enable check
*/
qca8075_phy_mmd_write(0, phy, 7, 0x8029, 0x0000);
qca8075_phy_mmd_write(0, phy, 7, 0x8029, 0x0003);
/*
* Start traffic
*/
qca8075_phy_mmd_write(0, phy, 7, 0x8020, 0xa000);
mdelay(200);
/*
* check counter
*/
tx_counter_ok = qca8075_phy_mmd_read(0, phy, 7, 0x802e);
tx_counter_ok_high16 = qca8075_phy_mmd_read(0, phy, 7, 0x802d);
tx_counter_error = qca8075_phy_mmd_read(0, phy, 7, 0x802f);
rx_counter_ok = qca8075_phy_mmd_read(0, phy, 7, 0x802b);
rx_counter_ok_high16 = qca8075_phy_mmd_read(0, phy, 7, 0x802a);
rx_counter_error = qca8075_phy_mmd_read(0, phy, 7, 0x802c);
tx_ok = tx_counter_ok + (tx_counter_ok_high16 << 16);
rx_ok = rx_counter_ok + (rx_counter_ok_high16 << 16);
/*
* Success
*/
if((tx_ok == 0x3000) && (tx_counter_error == 0)) {
phy_t_status &= (~(1 << phy));
} else {
phy_t_status |= (1 << phy);
}
/*
* Power down
*/
qca8075_phy_reg_write(0, phy, 0x0, 0x1840);
}
/*
* Reset 5-phy
*/
qca8075_phy_reg_write(0, 0x1f, 0x0, 0x9000);
/*
* Enable 5-phy loopback
*/
qca8075_phy_reg_write(0, 0x1f, 0x0, 0x4140);
/*
* check link
*/
j = 0;
while (j < 100) {
for (phy = 0; phy < 5; phy++) {
status = qca8075_phy_reg_read(0, phy, 0x11);
if (!(status & (1 << 10)))
break;
}
if (phy >= 5)
break;
mdelay(10);
j++;
}
/*
* Enable check
*/
qca8075_phy_mmd_write(0, 0x1f, 7, 0x8029, 0x0000);
qca8075_phy_mmd_write(0, 0x1f, 7, 0x8029, 0x0003);
/*
* Start traffic
*/
qca8075_phy_mmd_write(0, 0x1f, 7, 0x8020, 0xa000);
mdelay(200);
for (phy = 0; phy < 5; phy++) {
/*
* Check counter
*/
tx_counter_ok = qca8075_phy_mmd_read(0, phy, 7, 0x802e);
tx_counter_ok_high16 = qca8075_phy_mmd_read(0, phy, 7, 0x802d);
tx_counter_error = qca8075_phy_mmd_read(0, phy, 7, 0x802f);
rx_counter_ok = qca8075_phy_mmd_read(0, phy, 7, 0x802b);
rx_counter_ok_high16 = qca8075_phy_mmd_read(0, phy, 7, 0x802a);
rx_counter_error = qca8075_phy_mmd_read(0, phy, 7, 0x802c);
tx_ok = tx_counter_ok + (tx_counter_ok_high16 << 16);
rx_ok = rx_counter_ok + (rx_counter_ok_high16 << 16);
debug("rx_ok: %d, tx_ok: %d", rx_ok, tx_ok);
debug("rx_counter_error: %d, tx_counter_error: %d",
rx_counter_error, tx_counter_error);
/*
* Success
*/
if ((tx_ok == 0x3000) && (tx_counter_error == 0)) {
phy_t_status &= (~(1 << (phy + 8)));
} else {
phy_t_status |= (1 << (phy + 8));
}
}
if (phy_t_status) {
qca8075_ess_reset();
} else {
break;
}
}
/*
* Configuration recover
*/
/*
* Packet number
*/
qca8075_phy_mmd_write(0, 0x1f, 7, 0x8021, 0x0);
/*
* Disable check
*/
qca8075_phy_mmd_write(0, 0x1f, 7, 0x8029, 0x0);
/*
* Disable traffic
*/
qca8075_phy_mmd_write(0, 0x1f, 7, 0x8020, 0x0);
}
void clear_self_test_config(void)
{
int phy = 0;
u32 value = 0;
/*
* Disable phy internal loopback
*/
qca8075_phy_reg_write(0, 0x1f, 0x10, 0x6860);
qca8075_phy_reg_write(0, 0x1f, 0x0, 0x9040);
for (phy = 0; phy < 5; phy++) {
value = readl(0xc00066c + (phy * 0xc));
/*
* Disable mac loop back
*/
writel((value&(~(1 << 21))), (0xc00066c + (phy * 0xc)));
/*
* Disable phy mdio broadcast writei
*/
qca8075_phy_mmd_write(0, phy, 7, 0x8028, 0x001f);
}
}
int ipq40xx_qca8075_phy_init(struct ipq40xx_eth_dev *info)
{
u16 phy_data;
u32 phy_id = 0;
struct phy_ops *qca8075_ops;
qca8075_ops = (struct phy_ops *)malloc(sizeof(struct phy_ops));
if (!qca8075_ops)
return -ENOMEM;
qca8075_ops->phy_get_link_status = qca8075_phy_get_link_status;
qca8075_ops->phy_get_speed = qca8075_phy_get_speed;
qca8075_ops->phy_get_duplex = qca8075_phy_get_duplex;
info->ops = qca8075_ops;
qca8075_id = phy_data = qca8075_phy_reg_read(0x0, 0x0, QCA8075_PHY_ID1);
printf ("PHY ID1: 0x%x\n", phy_data);
phy_data = qca8075_phy_reg_read(0x0, 0x0, QCA8075_PHY_ID2);
printf ("PHY ID2: 0x%x\n", phy_data);
qca8075_id = (qca8075_id << 16) | phy_data;
if (qca8075_id == QCA8075_PHY_V1_0_5P) {
phy_data = qca8075_phy_mmd_read(0, PSGMII_ID,
QCA8075_PHY_MMD1_NUM, QCA8075_PSGMII_FIFI_CTRL);
phy_data &= 0xbfff;
qca8075_phy_mmd_write(0, PSGMII_ID, QCA8075_PHY_MMD1_NUM,
QCA8075_PSGMII_FIFI_CTRL, phy_data);
}
/*
* Enable AZ transmitting ability
*/
qca8075_phy_mmd_write(0, PSGMII_ID, QCA8075_PHY_MMD1_NUM,
QCA8075_PSGMII_MODE_CTRL,
QCA8075_PHY_PSGMII_MODE_CTRL_ADJUST_VALUE);
/*
* Enable phy power saving function by default
*/
if (qca8075_id == QCA8075_PHY_V1_1_2P)
phy_id = 3;
if ((qca8075_id == QCA8075_PHY_V1_0_5P) ||
(qca8075_id == QCA8075_PHY_V1_1_5P) ||
(qca8075_id == QCA8075_PHY_V1_1_2P)) {
for (; phy_id < 5; phy_id++) {
qca8075_phy_set_8023az(0x0, phy_id, 0x1);
qca8075_phy_set_powersave(0x0, phy_id, 0x1);
qca8075_phy_set_hibernate(0x0, phy_id, 0x1);
}
}
phy_data = qca8075_phy_mmd_read(0, 4, QCA8075_PHY_MMD3_NUM, 0x805a);
phy_data &= (~(1 << 1));
qca8075_phy_mmd_write(0, 4, QCA8075_PHY_MMD3_NUM, 0x805a, phy_data);
return 0;
}

View file

@ -0,0 +1,480 @@
/*
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
* 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
* GNU General Public License for more details.
*/
#ifndef _QCA8075_PHY_H_
#define _QCA8075_PHY_H_
#define QCA8075_PHY_V1_0_5P 0x004DD0B0
#define QCA8075_PHY_V1_1_5P 0x004DD0B1
#define QCA8075_PHY_V1_1_2P 0x004DD0B2
#define QCA8075_PHY_CONTROL 0
#define QCA8075_PHY_STATUS 1
#define QCA8075_PHY_ID1 2
#define QCA8075_PHY_ID2 3
#define QCA8075_AUTONEG_ADVERT 4
#define QCA8075_LINK_PARTNER_ABILITY 5
#define QCA8075_AUTONEG_EXPANSION 6
#define QCA8075_NEXT_PAGE_TRANSMIT 7
#define QCA8075_LINK_PARTNER_NEXT_PAGE 8
#define QCA8075_1000BASET_CONTROL 9
#define QCA8075_1000BASET_STATUS 10
#define QCA8075_MMD_CTRL_REG 13
#define QCA8075_MMD_DATA_REG 14
#define QCA8075_EXTENDED_STATUS 15
#define QCA8075_PHY_SPEC_CONTROL 16
#define QCA8075_PHY_SPEC_STATUS 17
#define QCA8075_PHY_INTR_MASK 18
#define QCA8075_PHY_INTR_STATUS 19
#define QCA8075_PHY_CDT_CONTROL 22
#define QCA8075_PHY_CDT_STATUS 28
#define QCA8075_DEBUG_PORT_ADDRESS 29
#define QCA8075_DEBUG_PORT_DATA 30
#define COMBO_PHY_ID 4
#define PSGMII_ID 5
#define QCA8075_DEBUG_PHY_HIBERNATION_CTRL 0xb
#define QCA8075_DEBUG_PHY_POWER_SAVING_CTRL 0x29
#define QCA8075_PHY_MMD7_ADDR_8023AZ_EEE_CTRL 0x3c
#define QCA8075_PHY_MMD3_ADDR_REMOTE_LOOPBACK_CTRL 0x805a
#define QCA8075_PHY_MMD3_WOL_MAGIC_MAC_CTRL1 0x804a
#define QCA8075_PHY_MMD3_WOL_MAGIC_MAC_CTRL2 0x804b
#define QCA8075_PHY_MMD3_WOL_MAGIC_MAC_CTRL3 0x804c
#define QCA8075_PHY_MMD3_WOL_CTRL 0x8012
#define QCA8075_PSGMII_FIFI_CTRL 0x6e
#define QCA8075_PSGMII_CALIB_CTRL 0x27
#define QCA8075_PSGMII_MODE_CTRL 0x6d
#define QCA8075_PHY_PSGMII_MODE_CTRL_ADJUST_VALUE 0x220c
#define QCA8075_PHY_MMD7_NUM 7
#define QCA8075_PHY_MMD3_NUM 3
#define QCA8075_PHY_MMD1_NUM 1
#define QCA8075_PHY_SGMII_STATUS 0x1a /* sgmii_status Register */
#define QCA8075_PHY4_AUTO_SGMII_SELECT 0x40
#define QCA8075_PHY4_AUTO_COPPER_SELECT 0x20
#define QCA8075_PHY4_AUTO_BX1000_SELECT 0x10
#define QCA8075_PHY4_AUTO_FX100_SELECT 0x8
#define QCA8075_PHY_CHIP_CONFIG 0x1f /* Chip Configuration Register */
#define BT_BX_SG_REG_SELECT BIT_15
#define BT_BX_SG_REG_SELECT_OFFSET 15
#define BT_BX_SG_REG_SELECT_LEN 1
#define QCA8075_SG_BX_PAGES 0x0
#define QCA8075_SG_COPPER_PAGES 0x1
#define QCA8075_PHY_PSGMII_BASET 0x0
#define QCA8075_PHY_PSGMII_BX1000 0x1
#define QCA8075_PHY_PSGMII_FX100 0x2
#define QCA8075_PHY_PSGMII_AMDET 0x3
#define QCA8075_PHY_SGMII_BASET 0x4
#define QCA8075_PHY4_PREFER_FIBER 0x400
#define PHY4_PREFER_COPPER 0x0
#define PHY4_PREFER_FIBER 0x1
#define QCA8075_PHY4_FIBER_MODE_1000BX 0x100
#define AUTO_100FX_FIBER 0x0
#define AUTO_1000BX_FIBER 0x1
#define QCA8075_PHY_MDIX 0x0020
#define QCA8075_PHY_MDIX_AUTO 0x0060
#define QCA8075_PHY_MDIX_STATUS 0x0040
#define MODE_CFG_QUAL BIT_4
#define MODE_CFG_QUAL_OFFSET 4
#define MODE_CFG_QUAL_LEN 4
#define MODE_CFG BIT_0
#define MODE_CFG_OFFSET 0
#define MODE_CFG_LEN 4
#define QCA8075_PHY_MMD3_ADDR_8023AZ_CLD_CTRL 0x8007
#define QCA8075_PHY_MMD3_ADDR_8023AZ_TIMER_CTRL 0x804e
#define QCA8075_PHY_MMD3_ADDR_CLD_CTRL5 0x8005
#define QCA8075_PHY_MMD3_ADDR_CLD_CTRL3 0x8003
#define AZ_TIMER_CTRL_DEFAULT_VALUE 0x3062
#define AZ_CLD_CTRL_DEFAULT_VALUE 0x83f6
#define AZ_TIMER_CTRL_ADJUST_VALUE 0x7062
#define AZ_CLD_CTRL_ADJUST_VALUE 0x8396
/*debug port */
#define QCA8075_DEBUG_PORT_RGMII_MODE 18
#define QCA8075_DEBUG_PORT_RGMII_MODE_EN 0x0008
#define QCA8075_DEBUG_PORT_RX_DELAY 0
#define QCA8075_DEBUG_PORT_RX_DELAY_EN 0x8000
#define QCA8075_DEBUG_PORT_TX_DELAY 5
#define QCA8075_DEBUG_PORT_TX_DELAY_EN 0x0100
/* PHY Registers Field */
/* Control Register fields offset:0 */
/* bits 6,13: 10=1000, 01=100, 00=10 */
#define QCA8075_CTRL_SPEED_MSB 0x0040
/* Collision test enable */
#define QCA8075_CTRL_COLL_TEST_ENABLE 0x0080
/* FDX =1, half duplex =0 */
#define QCA8075_CTRL_FULL_DUPLEX 0x0100
/* Restart auto negotiation */
#define QCA8075_CTRL_RESTART_AUTONEGOTIATION 0x0200
/* Isolate PHY from MII */
#define QCA8075_CTRL_ISOLATE 0x0400
/* Power down */
#define QCA8075_CTRL_POWER_DOWN 0x0800
/* Auto Neg Enable */
#define QCA8075_CTRL_AUTONEGOTIATION_ENABLE 0x1000
/* Local Loopback Enable */
#define QCA8075_LOCAL_LOOPBACK_ENABLE 0x4000
/* bits 6,13: 10=1000, 01=100, 00=10 */
#define QCA8075_CTRL_SPEED_LSB 0x2000
/* 0 = normal, 1 = loopback */
#define QCA8075_CTRL_LOOPBACK 0x4000
#define QCA8075_CTRL_SOFTWARE_RESET 0x8000
#define QCA8075_CTRL_SPEED_MASK 0x2040
#define QCA8075_CTRL_SPEED_1000 0x0040
#define QCA8075_CTRL_SPEED_100 0x2000
#define QCA8075_CTRL_SPEED_10 0x0000
#define QCA8075_RESET_DONE(phy_control) \
(((phy_control) & (QCA8075_CTRL_SOFTWARE_RESET)) == 0)
/* Status Register fields offset:1 */
/* Extended register capabilities */
#define QCA8075_STATUS_EXTENDED_CAPS 0x0001
/* Jabber Detected */
#define QCA8075_STATUS_JABBER_DETECT 0x0002
/* Link Status 1 = link */
#define QCA8075_STATUS_LINK_STATUS_UP 0x0004
/* Auto Neg Capable */
#define QCA8075_STATUS_AUTONEG_CAPS 0x0008
/* Remote Fault Detect */
#define QCA8075_STATUS_REMOTE_FAULT 0x0010
/* Auto Neg Complete */
#define QCA8075_STATUS_AUTO_NEG_DONE 0x0020
/* Preamble may be suppressed */
#define QCA8075_STATUS_PREAMBLE_SUPPRESS 0x0040
/* Ext. status info in Reg 0x0F */
#define QCA8075_STATUS_EXTENDED_STATUS 0x0100
/* 100T2 Half Duplex Capable */
#define QCA8075_STATUS_100T2_HD_CAPS 0x0200
/* 100T2 Full Duplex Capable */
#define QCA8075_STATUS_100T2_FD_CAPS 0x0400
/* 10T Half Duplex Capable */
#define QCA8075_STATUS_10T_HD_CAPS 0x0800
/* 10T Full Duplex Capable */
#define QCA8075_STATUS_10T_FD_CAPS 0x1000
/* 100X Half Duplex Capable */
#define QCA8075_STATUS_100X_HD_CAPS 0x2000
/* 100X Full Duplex Capable */
#define QCA8075_STATUS_100X_FD_CAPS 0x4000
/* 100T4 Capable */
#define QCA8075_STATUS_100T4_CAPS 0x8000
/* extended status register capabilities */
#define QCA8075_STATUS_1000T_HD_CAPS 0x1000
#define QCA8075_STATUS_1000T_FD_CAPS 0x2000
#define QCA8075_STATUS_1000X_HD_CAPS 0x4000
#define QCA8075_STATUS_1000X_FD_CAPS 0x8000
#define QCA8075_AUTONEG_DONE(ip_phy_status) \
(((ip_phy_status) & (QCA8075_STATUS_AUTO_NEG_DONE)) == \
(QCA8075_STATUS_AUTO_NEG_DONE))
/* PHY identifier1 offset:2 */
//Organizationally Unique Identifier bits 3:18
/* PHY identifier2 offset:3 */
//Organizationally Unique Identifier bits 19:24
/* Auto-Negotiation Advertisement register. offset:4 */
/* indicates IEEE 802.3 CSMA/CD */
#define QCA8075_ADVERTISE_SELECTOR_FIELD 0x0001
/* 10T Half Duplex Capable */
#define QCA8075_ADVERTISE_10HALF 0x0020
/* 10T Full Duplex Capable */
#define QCA8075_ADVERTISE_10FULL 0x0040
/* 100TX Half Duplex Capable */
#define QCA8075_ADVERTISE_100HALF 0x0080
/* 100TX Full Duplex Capable */
#define QCA8075_ADVERTISE_100FULL 0x0100
/* 100T4 Capable */
#define QCA8075_ADVERTISE_100T4 0x0200
/* Pause operation desired */
#define QCA8075_ADVERTISE_PAUSE 0x0400
/* Asymmetric Pause Direction bit */
#define QCA8075_ADVERTISE_ASYM_PAUSE 0x0800
/* Remote Fault detected */
#define QCA8075_ADVERTISE_REMOTE_FAULT 0x2000
/* Next Page ability supported */
#define QCA8075_ADVERTISE_NEXT_PAGE 0x8000
/* 100TX Half Duplex Capable */
#define QCA8075_ADVERTISE_1000HALF 0x0100
/* 100TX Full Duplex Capable */
#define QCA8075_ADVERTISE_1000FULL 0x0200
#define QCA8075_ADVERTISE_ALL \
(QCA8075_ADVERTISE_10HALF | QCA8075_ADVERTISE_10FULL | \
QCA8075_ADVERTISE_100HALF | QCA8075_ADVERTISE_100FULL | \
QCA8075_ADVERTISE_1000FULL)
#define QCA8075_ADVERTISE_MEGA_ALL \
(QCA8075_ADVERTISE_10HALF | QCA8075_ADVERTISE_10FULL | \
QCA8075_ADVERTISE_100HALF | QCA8075_ADVERTISE_100FULL)
#define QCA8075_BX_ADVERTISE_1000FULL 0x0020
#define QCA8075_BX_ADVERTISE_1000HALF 0x0040
#define QCA8075_BX_ADVERTISE_PAUSE 0x0080
#define QCA8075_BX_ADVERTISE_ASYM_PAUSE 0x0100
#define QCA8075_BX_ADVERTISE_ALL \
(QCA8075_BX_ADVERTISE_ASYM_PAUSE | QCA8075_BX_ADVERTISE_PAUSE | \
QCA8075_BX_ADVERTISE_1000HALF | QCA8075_BX_ADVERTISE_1000FULL)
/* Link Partner ability offset:5 */
/* Same as advertise selector */
#define QCA8075_LINK_SLCT 0x001f
/* Can do 10mbps half-duplex */
#define QCA8075_LINK_10BASETX_HALF_DUPLEX 0x0020
/* Can do 10mbps full-duplex */
#define QCA8075_LINK_10BASETX_FULL_DUPLEX 0x0040
/* Can do 100mbps half-duplex */
#define QCA8075_LINK_100BASETX_HALF_DUPLEX 0x0080
/* Can do 100mbps full-duplex */
#define QCA8075_LINK_100BASETX_FULL_DUPLEX 0x0100
/* Can do 1000mbps full-duplex */
#define QCA8075_LINK_1000BASETX_FULL_DUPLEX 0x0800
/* Can do 1000mbps half-duplex */
#define QCA8075_LINK_1000BASETX_HALF_DUPLEX 0x0400
/* 100BASE-T4 */
#define QCA8075_LINK_100BASE4 0x0200
/* PAUSE */
#define QCA8075_LINK_PAUSE 0x0400
/* Asymmetrical PAUSE */
#define QCA8075_LINK_ASYPAUSE 0x0800
/* Link partner faulted */
#define QCA8075_LINK_RFAULT 0x2000
/* Link partner acked us */
#define QCA8075_LINK_LPACK 0x4000
/* Next page bit */
#define QCA8075_LINK_NPAGE 0x8000
/* Auto-Negotiation Expansion Register offset:6 */
/* Next Page Transmit Register offset:7 */
/* Link partner Next Page Register offset:8 */
/* 1000BASE-T Control Register offset:9 */
/* Advertise 1000T HD capability */
#define QCA8075_CTL_1000T_HD_CAPS 0x0100
/* Advertise 1000T FD capability */
#define QCA8075_CTL_1000T_FD_CAPS 0x0200
/* 1=Repeater/switch device port 0=DTE device */
#define QCA8075_CTL_1000T_REPEATER_DTE 0x0400
/* 1=Configure PHY as Master 0=Configure PHY as Slave */
#define QCA8075_CTL_1000T_MS_VALUE 0x0800
/* 1=Master/Slave manual config value 0=Automatic Master/Slave config */
#define QCA8075_CTL_1000T_MS_ENABLE 0x1000
/* Normal Operation */
#define QCA8075_CTL_1000T_TEST_MODE_NORMAL 0x0000
/* Transmit Waveform test */
#define QCA8075_CTL_1000T_TEST_MODE_1 0x2000
/* Master Transmit Jitter test */
#define QCA8075_CTL_1000T_TEST_MODE_2 0x4000
/* Slave Transmit Jitter test */
#define QCA8075_CTL_1000T_TEST_MODE_3 0x6000
/* Transmitter Distortion test */
#define QCA8075_CTL_1000T_TEST_MODE_4 0x8000
#define QCA8075_CTL_1000T_SPEED_MASK 0x0300
#define QCA8075_CTL_1000T_DEFAULT_CAP_MASK 0x0300
/* 1000BASE-T Status Register offset:10 */
/* LP is 1000T HD capable */
#define QCA8075_STATUS_1000T_LP_HD_CAPS 0x0400
/* LP is 1000T FD capable */
#define QCA8075_STATUS_1000T_LP_FD_CAPS 0x0800
/* Remote receiver OK */
#define QCA8075_STATUS_1000T_REMOTE_RX_STATUS 0x1000
/* Local receiver OK */
#define QCA8075_STATUS_1000T_LOCAL_RX_STATUS 0x2000
/* 1=Local TX is Master, 0=Slave */
#define QCA8075_STATUS_1000T_MS_CONFIG_RES 0x4000
#define QCA8075_STATUS_1000T_MS_CONFIG_FAULT 0x8000
/* Master/Slave config fault */
#define QCA8075_STATUS_1000T_REMOTE_RX_STATUS_SHIFT 12
#define QCA8075_STATUS_1000T_LOCAL_RX_STATUS_SHIFT 13
/* Phy Specific Control Register offset:16 */
/* 1=Jabber Function disabled */
#define QCA8075_CTL_JABBER_DISABLE 0x0001
/* 1=Polarity Reversal enabled */
#define QCA8075_CTL_POLARITY_REVERSAL 0x0002
/* 1=SQE Test enabled */
#define QCA8075_CTL_SQE_TEST 0x0004
#define QCA8075_CTL_MAC_POWERDOWN 0x0008
/* 1=CLK125 low, 0=CLK125 toggling
#define QCA8075_CTL_CLK125_DISABLE 0x0010
*/
/* MDI Crossover Mode bits 6:5 */
/* Manual MDI configuration */
#define QCA8075_CTL_MDI_MANUAL_MODE 0x0000
/* Manual MDIX configuration */
#define QCA8075_CTL_MDIX_MANUAL_MODE 0x0020
/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
#define QCA8075_CTL_AUTO_X_1000T 0x0040
/* Auto crossover enabled all speeds */
#define QCA8075_CTL_AUTO_X_MODE 0x0060
/* 1=Enable Extended 10BASE-T distance
* (Lower 10BASE-T RX Threshold)
* 0=Normal 10BASE-T RX Threshold */
#define QCA8075_CTL_10BT_EXT_DIST_ENABLE 0x0080
/* 1=5-Bit interface in 100BASE-TX
* 0=MII interface in 100BASE-TX */
#define QCA8075_CTL_MII_5BIT_ENABLE 0x0100
/* 1=Scrambler disable */
#define QCA8075_CTL_SCRAMBLER_DISABLE 0x0200
/* 1=Force link good */
#define QCA8075_CTL_FORCE_LINK_GOOD 0x0400
/* 1=Assert CRS on Transmit */
#define QCA8075_CTL_ASSERT_CRS_ON_TX 0x0800
#define QCA8075_CTL_POLARITY_REVERSAL_SHIFT 1
#define QCA8075_CTL_AUTO_X_MODE_SHIFT 5
#define QCA8075_CTL_10BT_EXT_DIST_ENABLE_SHIFT 7
/* Phy Specific status fields offset:17 */
/* 1=Speed & Duplex resolved */
#define QCA8075_STATUS_LINK_PASS 0x0400
#define QCA8075_STATUS_RESOVLED 0x0800
/* 1=Duplex 0=Half Duplex */
#define QCA8075_STATUS_FULL_DUPLEX 0x2000
/* Speed, bits 14:15 */
#define QCA8075_STATUS_SPEED 0xC000
#define QCA8075_STATUS_SPEED_MASK 0xC000
/* 00=10Mbs */
#define QCA8075_STATUS_SPEED_10MBS 0x0000
/* 01=100Mbs */
#define QCA8075_STATUS_SPEED_100MBS 0x4000
/* 10=1000Mbs */
#define QCA8075_STATUS_SPEED_1000MBS 0x8000
#define QCA8075_SPEED_DUPLEX_RESOVLED(phy_status) \
(((phy_status) & \
(QCA8075_STATUS_RESOVLED)) == \
(QCA8075_STATUS_RESOVLED))
/*phy debug port1 register offset:29 */
/*phy debug port2 register offset:30 */
/*QCA8075 interrupt flag */
#define QCA8075_INTR_SPEED_CHANGE 0x4000
#define QCA8075_INTR_DUPLEX_CHANGE 0x2000
#define QCA8075_INTR_STATUS_UP_CHANGE 0x0400
#define QCA8075_INTR_STATUS_DOWN_CHANGE 0x0800
#define QCA8075_INTR_BX_FX_STATUS_DOWN_CHANGE 0x0100
#define QCA8075_INTR_BX_FX_STATUS_UP_CHANGE 0x0080
#define QCA8075_INTR_MEDIA_STATUS_CHANGE 0x1000
#define QCA8075_INTR_WOL 0x0001
#define QCA8075_INTR_POE 0x0002
#define RUN_CDT 0x8000
#define CABLE_LENGTH_UNIT 0x0400
#define QCA8075_MAX_TRIES 100
#endif /* _QCA8075_PHY_H_ */