ipq5018: update ethernet initialization sequence

This change make the qca_8337 switch initialization generic based on
dts irrespective of gmac controller.

Signed-off-by: Vandhiadevan Karunamoorthy <vkarunam@codeaurora.org>
Change-Id: I292992307ead2cd7bbb0763ff483dc16c266d417
This commit is contained in:
Vandhiadevan Karunamoorthy 2020-09-29 16:56:15 +05:30
parent e83a9121f5
commit 7fff6b863d
7 changed files with 245 additions and 135 deletions

View file

@ -128,6 +128,11 @@
unit = <0>;
base = <0x39C00000>;
phy_address = <7>;
phy_external_link = <0>;
mac_pwr = <0xaa545>;
s17c_switch_enable = <1>;
switch_port_count = <4>;
switch_phy_address = <0 1 2 3>;
};
gmac2_cfg {
unit = <1>;

View file

@ -134,6 +134,11 @@
unit = <0>;
base = <0x39C00000>;
phy_address = <7>;
phy_external_link = <0>;
mac_pwr = <0xaa545>;
s17c_switch_enable = <1>;
switch_port_count = <4>;
switch_phy_address = <0 1 2 3>;
};
gmac2_cfg {
unit = <1>;

View file

@ -17,14 +17,28 @@
#include <net.h>
#include <configs/ipq5018.h>
#define LINK(_data) (_data & 0x400)? "Up" : "Down"
#define DUPLEX(_data) (_data & 0x2000)? "Full duplex" : "Half duplex"
#define SPEED(_data) ((_data & 0xC000) >> 12)
#define SPEED_1000M (1 << 3)
#define SPEED_100M (1 << 2)
#define QCA808X_MII_ADDR_C45 (1<<30)
#define QCA808X_REG_C45_ADDRESS(dev_type, reg_num) \
(QCA808X_MII_ADDR_C45 | \
((dev_type & 0x1f) << 16) | \
(reg_num & 0xffff))
#define MPGE_PHY_MMD1_DAC 0x8100
#define MPGE_PHY_MMD1_NUM 0x1
#define MPGE_PHY_MMD1_DAC_MASK 0xff00
#define PHY_DAC(val) (val<<8)
#define MPGE_PHY_DEBUG_EDAC 0x4380
#define LINK_UP 0x400
#define LINK(_data) (_data & LINK_UP)? "Up" : "Down"
#define DUPLEX(_data) (_data & 0x2000)?\
"Full duplex" : "Half duplex"
#define SPEED(_data) ((_data & 0xC000) >> 12)
#define SPEED_1000M (1 << 3)
#define SPEED_100M (1 << 2)
#define GEPHY 0x004DD0C0
#define S17C 0x1302
#define S17C_VERSION 0x1302
#define QCA_8337 0x004DD036
#define CONFIG_MACRESET_TIMEOUT (3 * CONFIG_SYS_HZ)
#define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ)
@ -248,6 +262,7 @@ struct ipq_eth_dev {
uint phy_type;
uint mac_ps;
uint ipq_swith;
uint phy_external_link;
int link_printed;
u32 padding;
ipq_gmac_desc_t *desc_tx[NO_OF_TX_DESC];

View file

@ -1047,6 +1047,9 @@ int board_eth_init(bd_t *bis)
gmac_cfg[loop].phy_interface_mode = fdtdec_get_uint(gd->fdt_blob,
offset, "phy_interface_mode", 0);
gmac_cfg[loop].phy_external_link = fdtdec_get_uint(gd->fdt_blob,
offset, "phy_external_link", 0);
gmac_cfg[loop].phy_napa_gpio = fdtdec_get_uint(gd->fdt_blob,
offset, "napa_gpio", 0);
if (gmac_cfg[loop].phy_napa_gpio){

View file

@ -490,6 +490,7 @@ typedef struct {
int phy_type;
u32 mac_pwr;
int ipq_swith;
int phy_external_link;
int switch_port_count;
int switch_port_phy_address[S17C_MAX_PORT];
const char phy_name[MDIO_NAME_LEN];

View file

@ -173,7 +173,7 @@ int athrs17_init_switch(void)
data = athrs17_reg_read(S17_MASK_CTRL_REG);
i++;
if (i == 10){
printf("Failed to reset S17C \n");
printf("QCA_8337: Failed to reset\n");
return -1;
}
} while (data & S17_MASK_CTRL_SOFT_RET);

View file

@ -38,6 +38,7 @@ phy_info_t *phy_info[IPQ5018_PHY_MAX] = {0};
extern int ipq_mdio_read(int mii_id, int regnum, ushort *data);
extern int ipq_mdio_write(int mii_id, int regnum, u16 value);
extern int ipq5018_mdio_write(int mii_id, int regnum, u16 value);
extern int ipq5018_mdio_read(int mii_id, int regnum, ushort *data);
extern int ipq_qca8033_phy_init(struct phy_ops **ops, u32 phy_id);
extern int ipq_qca8081_phy_init(struct phy_ops **ops, u32 phy_id);
@ -316,9 +317,14 @@ static int ipq5018_s17c_Link_Update(struct ipq_eth_dev *priv)
priv->gmac_board_cfg->switch_port_phy_address[i],
0x11,
NULL);
if (phy_data == 0x50)
continue;
status = 0;
/* Atleast one port should be link up*/
if (phy_data & LINK_UP)
status = 0;
printf("Port%d %s ", i + 1, LINK(phy_data));
switch(SPEED(phy_data)){
@ -349,22 +355,19 @@ static int ipq5018_phy_link_update(struct eth_device *dev)
int speed_clock1 = 0, speed_clock2 = 0;
int mode = PORT_WRAPPER_SGMII0_RGMII4;
if (priv->ipq_swith == 0) {
phy_get_ops = priv->ops;
if ((phy_get_ops == NULL) ||
(phy_get_ops->phy_get_link_status == NULL) ||
(phy_get_ops->phy_get_speed == NULL) ||
(phy_get_ops->phy_get_duplex == NULL)) {
printf ("Link status/Get speed/Get duplex not mapped\n");
return -1;
}
}
phy_get_ops = priv->ops;
if (priv->ipq_swith) {
speed_clock1 = 1;
speed_clock2 = 0;
status = ipq5018_s17c_Link_Update(priv);
} else {
}
if (phy_get_ops != NULL &&
phy_get_ops->phy_get_link_status != NULL &&
phy_get_ops->phy_get_speed != NULL &&
phy_get_ops->phy_get_duplex != NULL){
status = phy_get_ops->phy_get_link_status(priv->mac_unit,
priv->phy_address);
phy_get_ops->phy_get_speed(priv->mac_unit,
@ -373,51 +376,53 @@ static int ipq5018_phy_link_update(struct eth_device *dev)
priv->phy_address, &duplex);
switch (speed) {
case FAL_SPEED_10:
speed_clock1 = 9;
speed_clock2 = 9;
priv->speed = MII_PORT_SELECT;
printf ("eth%d %s Speed :%d %s duplex\n",
priv->mac_unit,
lstatus[status], speed,
dp[duplex]);
break;
case FAL_SPEED_100:
priv->speed = MII_PORT_SELECT | FES_PORT_SPEED;
speed_clock1 = 9;
speed_clock2 = 0;
printf ("eth%d %s Speed :%d %s duplex\n",
priv->mac_unit,
lstatus[status], speed,
dp[duplex]);
break;
case FAL_SPEED_1000:
priv->speed = SGMII_PORT_SELECT;
speed_clock1 = 1;
speed_clock2 = 0;
printf ("eth%d %s Speed :%d %s duplex\n",
priv->mac_unit,
lstatus[status], speed,
dp[duplex]);
break;
case FAL_SPEED_2500:
priv->speed = SGMII_PORT_SELECT;
mode = PORT_WRAPPER_SGMII_PLUS;
speed_clock1 = 1;
speed_clock2 = 0;
printf ("eth%d %s Speed :%d %s duplex\n",
priv->mac_unit,
lstatus[status], speed,
dp[duplex]);
break;
default:
printf("Unknown speed\n");
break;
case FAL_SPEED_10:
speed_clock1 = 9;
speed_clock2 = 9;
priv->speed = MII_PORT_SELECT;
printf ("eth%d %s Speed :%d %s duplex\n",
priv->mac_unit,
lstatus[status], speed,
dp[duplex]);
break;
case FAL_SPEED_100:
priv->speed = MII_PORT_SELECT | FES_PORT_SPEED;
speed_clock1 = 9;
speed_clock2 = 0;
printf ("eth%d %s Speed :%d %s duplex\n",
priv->mac_unit,
lstatus[status], speed,
dp[duplex]);
break;
case FAL_SPEED_1000:
priv->speed = SGMII_PORT_SELECT;
speed_clock1 = 1;
speed_clock2 = 0;
printf ("eth%d %s Speed :%d %s duplex\n",
priv->mac_unit,
lstatus[status], speed,
dp[duplex]);
break;
case FAL_SPEED_2500:
priv->speed = SGMII_PORT_SELECT;
mode = PORT_WRAPPER_SGMII_PLUS;
speed_clock1 = 1;
speed_clock2 = 0;
printf ("eth%d %s Speed :%d %s duplex\n",
priv->mac_unit,
lstatus[status], speed,
dp[duplex]);
break;
default:
printf("Unknown speed\n");
break;
}
}
if (status) {
/* No PHY link is alive */
if (priv->ipq_swith == 0 && phy_get_ops == NULL)
printf("Link status/Get speed/Get duplex not mapped\n");
return -1;
}
@ -592,6 +597,118 @@ static void ipq_eth_halt(struct eth_device *dev)
ipq_mac_reset(dev);
}
static int QCA8337_switch_init(ipq_gmac_board_cfg_t *gmac_cfg)
{
for (int port = 0;
port < gmac_cfg->switch_port_count;
++port) {
u32 phy_val;
/* phy powerdown */
ipq_mdio_write(
gmac_cfg->switch_port_phy_address[port],
0x0,
0x0800
);
phy_val = ipq_mdio_read(
gmac_cfg->switch_port_phy_address[port],
0x3d,
NULL
);
phy_val &= ~0x0040;
ipq_mdio_write(
gmac_cfg->switch_port_phy_address[port],
0x3d,
phy_val
);
/*
* PHY will stop the tx clock for a while when link is down
* en_anychange debug port 0xb bit13 = 0 //speed up link down tx_clk
* sel_rst_80us debug port 0xb bit10 = 0 //speed up speed mode change to 2'b10 tx_clk
*/
phy_val = ipq_mdio_read(
gmac_cfg->switch_port_phy_address[port],
0xb,
NULL
);
phy_val &= ~0x2400;
ipq_mdio_write(
gmac_cfg->switch_port_phy_address[port],
0xb,
phy_val
);
mdelay(100);
}
if (ipq_athrs17_init(gmac_cfg) != 0){
printf("QCA_8337 switch init failed \n");
return 0;
}
for (int port = 0;
port < gmac_cfg->switch_port_count;
++port) {
ipq_mdio_write(
gmac_cfg->switch_port_phy_address[port],
MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM
);
/* phy reg 0x9, b10,1 = Prefer multi-port device (master) */
ipq_mdio_write(
gmac_cfg->switch_port_phy_address[port],
MII_CTRL1000,
(0x0400|ADVERTISE_1000FULL)
);
ipq_mdio_write(
gmac_cfg->switch_port_phy_address[port],
MII_BMCR,
BMCR_RESET | BMCR_ANENABLE
);
mdelay(100);
}
return 1;
}
static void gephy_mdac_edac_config(ipq_gmac_board_cfg_t *gmac_cfg)
{
uint16_t phy_data;
uint32_t phy_dac = PHY_DAC(0x10);
uint32_t C45_id = QCA808X_REG_C45_ADDRESS(MPGE_PHY_MMD1_NUM,
MPGE_PHY_MMD1_DAC);
/*set mdac value*/
phy_data = ipq5018_mdio_read(
gmac_cfg->phy_addr,
C45_id,
NULL
);
phy_data &= ~(MPGE_PHY_MMD1_DAC_MASK);
ipq5018_mdio_write(
gmac_cfg->phy_addr,
C45_id,
(phy_data | phy_dac)
);
mdelay(1);
/*set edac value*/
phy_data = ipq5018_mdio_read(
gmac_cfg->phy_addr,
MPGE_PHY_DEBUG_EDAC,
NULL
);
phy_data &= ~(MPGE_PHY_MMD1_DAC_MASK);
ipq5018_mdio_write(
gmac_cfg->phy_addr,
MPGE_PHY_DEBUG_EDAC,
(phy_data | phy_dac)
);
mdelay(1);
}
static void mdio_init(void)
{
if(ipq5018_sw_mdio_init("IPQ MDIO0"))
printf("MDIO Failed to init for GMAC0\n");
if(ipq_sw_mdio_init("IPQ MDIO1"))
printf("MDIO Failed to init for GMAC1\n");
}
int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg)
{
struct eth_device *dev[CONFIG_IPQ_NO_MACS];
@ -601,6 +718,9 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg)
int ret;
memset(enet_addr, 0, sizeof(enet_addr));
/* Mdio init */
mdio_init();
/* Getting the MAC address from ART partition */
ret = get_eth_mac_address(enet_addr, CONFIG_IPQ_NO_MACS);
@ -656,80 +776,35 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg)
ipq_gmac_macs[i]->gmac_board_cfg = gmac_cfg;
ipq_gmac_macs[i]->interface = gmac_cfg->phy_interface_mode;
ipq_gmac_macs[i]->phy_type = gmac_cfg->phy_type;
ipq_gmac_macs[i]->ipq_swith = gmac_cfg->ipq_swith;
ipq_gmac_macs[i]->phy_external_link = gmac_cfg->phy_external_link;
snprintf((char *)ipq_gmac_macs[i]->phy_name,
sizeof(ipq_gmac_macs[i]->phy_name), "IPQ MDIO%d", i);
phy_chip_id = -1;
if (gmac_cfg->unit){
ret = ipq_sw_mdio_init(ipq_gmac_macs[i]->phy_name);
if (ret)
goto init_failed;
if (ipq_gmac_macs[i]->ipq_swith){
/* S17C switch Id */
phy_chip_id = S17C;
for (int port = 0;
port < gmac_cfg->switch_port_count;
++port) {
u32 phy_val;
/* phy powerdown */
ipq_mdio_write(port, 0x0, 0x0800);
phy_val = ipq_mdio_read(port, 0x3d, NULL);
phy_val &= ~0x0040;
ipq_mdio_write(port, 0x3d, phy_val);
/*
* PHY will stop the tx clock for a while when link is down
* en_anychange debug port 0xb bit13 = 0 //speed up link down tx_clk
* sel_rst_80us debug port 0xb bit10 = 0 //speed up speed mode change to 2'b10 tx_clk
*/
phy_val = ipq_mdio_read(port, 0xb, NULL);
phy_val &= ~0x2400;
ipq_mdio_write(port, 0xb, phy_val);
mdelay(100);
}
if (ipq_athrs17_init(gmac_cfg) != 0){
printf("S17C switch init failed port \n");
}
for (int port = 0;
port < gmac_cfg->switch_port_count;
++port) {
ipq_mdio_write(port, MII_ADVERTISE, ADVERTISE_ALL |
ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
/*
* phy reg 0x9, b10,1 = Prefer multi-port device (master)
*/
ipq_mdio_write(port, MII_CTRL1000, (0x0400|ADVERTISE_1000FULL));
ipq_mdio_write(port, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
mdelay(100);
}
} else {
phy_chip_id1 = ipq_mdio_read(
ipq_gmac_macs[i]->phy_address,
QCA_PHY_ID1, NULL);
phy_chip_id2 = ipq_mdio_read(
ipq_gmac_macs[i]->phy_address,
QCA_PHY_ID2, NULL);
phy_chip_id = (phy_chip_id1 << 16) | phy_chip_id2;
}
phy_chip_id1 = ipq_mdio_read(
ipq_gmac_macs[i]->phy_address,
QCA_PHY_ID1,
NULL);
phy_chip_id2 = ipq_mdio_read(
ipq_gmac_macs[i]->phy_address,
QCA_PHY_ID2,
NULL);
phy_chip_id = (phy_chip_id1 << 16) | phy_chip_id2;
} else {
ret = ipq5018_sw_mdio_init(ipq_gmac_macs[i]->phy_name);
if (ret)
goto init_failed;
phy_chip_id1 = ipq5018_mdio_read(ipq_gmac_macs[i]->phy_address,
QCA_PHY_ID1, NULL);
phy_chip_id2 = ipq5018_mdio_read(ipq_gmac_macs[i]->phy_address,
QCA_PHY_ID2, NULL);
phy_chip_id1 = ipq5018_mdio_read(
ipq_gmac_macs[i]->phy_address,
QCA_PHY_ID1,
NULL);
phy_chip_id2 = ipq5018_mdio_read(
ipq_gmac_macs[i]->phy_address,
QCA_PHY_ID2,
NULL);
phy_chip_id = (phy_chip_id1 << 16) | phy_chip_id2;
}
switch(phy_chip_id) {
#ifdef CONFIG_QCA8081_PHY
/*
* NAPA PHY For GMAC1
*/
/* NAPA PHY For GMAC1 */
case QCA8081_PHY:
case QCA8081_1_1_PHY:
ipq_gmac_macs[i]->phy_type = QCA8081_1_1_PHY;
@ -738,19 +813,17 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg)
ipq_gmac_macs[i]->phy_address);
break;
#endif
/*
* Internel GEPHY only for GMAC0
*/
/* Internel GEPHY only for GMAC0 */
case GEPHY:
ipq_gmac_macs[i]->phy_type = GEPHY;
ipq_gephy_phy_init(
&ipq_gmac_macs[i]->ops,
ipq_gmac_macs[i]->phy_address);
if(ipq_gmac_macs[i]->phy_external_link)
gephy_mdac_edac_config(gmac_cfg);
break;
#ifdef CONFIG_QCA8033_PHY
/*
* 1G PHY
*/
/* 1G PHY */
case QCA8033_PHY:
ipq_gmac_macs[i]->phy_type = QCA8033_PHY;
ipq_qca8033_phy_init(
@ -758,21 +831,29 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg)
ipq_gmac_macs[i]->phy_address);
break;
#endif
case S17C:
case QCA_8337:
if(gmac_cfg->ipq_swith){
ipq_gmac_macs[i]->ipq_swith =
QCA8337_switch_init(gmac_cfg);
}
break;
default:
printf("GMAC%d : Invalid PHY ID \n", i);
printf("GMAC%d:Invalid PHY ID \n", i);
break;
}
/*
* Tx/Rx Descriptor initialization
*/
/* Initialize 8337 switch */
if (gmac_cfg->ipq_swith &&
ipq_gmac_macs[i]->phy_external_link &&
!ipq_gmac_macs[i]->ipq_swith){
ipq_gmac_macs[i]->ipq_swith =
QCA8337_switch_init(gmac_cfg);
}
/* Tx/Rx Descriptor initialization */
if (ipq_gmac_tx_rx_desc_ring(dev[i]->priv) == -1)
goto init_failed;
eth_register(dev[i]);
}
return 0;
init_failed: