blob: 214892486d2756f939cb34a9163ab57367481925 [file] [log] [blame]
/* Mediatek STAR MAC network driver.
*
* Copyright (c) 2016-2017 Mediatek Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*/
#include "star.h"
static void ex_phy_reset(star_dev *sdev, u32 id)
{
u16 val = 0;
val = star_mdc_mdio_read(sdev, id, 0);
val |= BMCR_RESET;
star_mdc_mdio_write(sdev, id, 0, val);
}
static void ex_phy_re_an(star_dev *dev, u32 id)
{
u16 val = 0;
val = star_mdc_mdio_read(dev, id, 0);
/* enable AN, and restart AN for SMSC PHY */
val |= BMCR_ANENABLE | BMCR_ANRESTART;
star_mdc_mdio_write(dev, id, 0, val);
}
static void ex_phy_dis_gpsi(star_dev *dev, u32 id)
{
u16 val = 0;
val = star_mdc_mdio_read(dev, id, 18);
val &= ~0x400;
star_mdc_mdio_write(dev, id, 18, val);
}
static void smsc8710a_phy_init(star_dev *sdev)
{
u32 phy_id = sdev->phy_ops->addr;
/* E2 ECO fixup the problem which 10M can't rx packet on E1 IC */
star_set_bit(star_dummy(sdev->base), STAR_DUMMY_E2_ECO);
/* for smsc8710a, after soft reset,
* AN is disabled, so enable it again
*/
ex_phy_reset(sdev, phy_id);
ex_phy_re_an(sdev, phy_id);
}
static struct eth_phy_ops smsc8710a_phy_ops = {
.phy_id = PHYID2_SMSC8710A,
.init = smsc8710a_phy_init,
};
static void dm9162_phy_init(star_dev *sdev)
{
u32 phy_id = sdev->phy_ops->addr;
ex_phy_reset(sdev, phy_id);
ex_phy_dis_gpsi(sdev, phy_id);
}
static struct eth_phy_ops dm9162_phy_ops = {
.phy_id = PHYID2_DM9162_XMII,
.init = dm9162_phy_init,
};
static void ksz8081mnx_phy_init(star_dev *sdev)
{
u32 data;
star_private *star_prv = sdev->star_prv;
/*set davicom phy register0 bit10 is 0 in MII for mt8160*/
data = star_mdc_mdio_read(sdev, star_prv->phy_addr, 0x0) & (~(1 << 10));
star_mdc_mdio_write(sdev, star_prv->phy_addr, 0x0, data);
data = star_mdc_mdio_read(sdev, star_prv->phy_addr, 0x0);
}
static struct eth_phy_ops ksz8081mnx_phy_ops = {
.phy_id = PHYID2_KSZ8081MNX,
.init = ksz8081mnx_phy_init,
};
static void default_phy_init(star_dev *sdev)
{
u32 phy_id = sdev->phy_ops->addr;
/* E2 ECO fixup the problem which 10M can't rx packet on E1 IC */
star_set_bit(star_dummy(sdev->base), STAR_DUMMY_E2_ECO);
ex_phy_reset(sdev, phy_id);
}
static struct eth_phy_ops default_phy_ops = {
.phy_id = 0,
.init = default_phy_init,
};
static void ip101g_az_disable(star_dev *dev, u32 id)
{
star_mdc_mdio_write(dev, id, 0x0d, 0x0007);
star_mdc_mdio_write(dev, id, 0x0e, 0x003c);
star_mdc_mdio_write(dev, id, 0x0d, 0x4007);
star_mdc_mdio_write(dev, id, 0x0e, 0x0000);
star_mdc_mdio_read(dev, id, 0x0e);
}
static void ip101g_anar_init(star_dev *sdev, u32 id)
{
u16 val = 0;
val = star_mdc_mdio_read(sdev, id, 4);
val &= ~(ADVERTISE_NPAGE | ADVERTISE_RFAULT | ADVERTISE_PAUSE_ASYM);
star_mdc_mdio_write(sdev, id, 4, val);
}
static void ip101g_phy_init(star_dev *sdev)
{
u32 phy_id = sdev->phy_ops->addr;
/* E2 ECO fixup the problem which 10M can't rx packet on E1 IC */
star_set_bit(star_dummy(sdev->base), STAR_DUMMY_E2_ECO);
ex_phy_reset(sdev, phy_id);
ip101g_az_disable(sdev, phy_id);
ip101g_anar_init(sdev, phy_id);
}
static struct eth_phy_ops ip101g_phy_ops = {
.phy_id = PHYID2_IP101G,
.init = ip101g_phy_init,
};
static void rtl8201fr_phy_init(star_dev *sdev)
{
u16 save_page;
u32 temp;
star_private *star_prv = sdev->star_prv;
/* save page */
save_page = star_mdc_mdio_read(sdev, star_prv->phy_addr, 31);
/* set to page0 */
star_mdc_mdio_write(sdev, star_prv->phy_addr, 31, 0x0000);
/* set register 0[15]=1 */
temp = star_mdc_mdio_read(sdev, star_prv->phy_addr, 0);
star_mdc_mdio_write(sdev, star_prv->phy_addr, 0, temp | (1 << 15));
/* set register 0[12]=0 */
temp = star_mdc_mdio_read(sdev, star_prv->phy_addr, 0);
star_mdc_mdio_write(sdev, star_prv->phy_addr, 0, temp & (~(1 << 12)));
/* set register 4[11]=0 */
temp = star_mdc_mdio_read(sdev, star_prv->phy_addr, 4);
star_mdc_mdio_write(sdev, star_prv->phy_addr, 4, temp & (~(1 << 11)));
/* set register 0[12]=1 */
temp = star_mdc_mdio_read(sdev, star_prv->phy_addr, 0);
star_mdc_mdio_write(sdev, star_prv->phy_addr, 0, temp | (1 << 12));
/* set page from save_page */
star_mdc_mdio_write(sdev, star_prv->phy_addr, 31, save_page);
save_page = star_mdc_mdio_read(sdev, star_prv->phy_addr, 31);
/* set page 4 */
star_mdc_mdio_write(sdev, star_prv->phy_addr, 31, 0x0004);
/* EEE_nway_disable */
star_mdc_mdio_write(sdev, star_prv->phy_addr, 16, 0x4077);
/* set to page0 */
star_mdc_mdio_write(sdev, star_prv->phy_addr, 31, 0x0000);
/* Set Address mode and MMD Device = 7 */
star_mdc_mdio_write(sdev, star_prv->phy_addr, 13, 0x0007);
/* Set Address Value */
star_mdc_mdio_write(sdev, star_prv->phy_addr, 14, 0x003C);
/* Set Data mode and MMD Device = 7 */
star_mdc_mdio_write(sdev, star_prv->phy_addr, 13, 0x4007);
/* turn off 100BASE-TX EEE capability */
star_mdc_mdio_write(sdev, star_prv->phy_addr, 14, 0x0000);
/* Restart Auto-Negotiation */
star_mdc_mdio_write(sdev, star_prv->phy_addr, 0, 0x1200);
star_mdc_mdio_write(sdev, star_prv->phy_addr, 31, save_page);
#if 0
save_page = star_mdc_mdio_read(sdev, star_prv->phy_addr, 31);
star_mdc_mdio_write(sdev, star_prv->phy_addr, 31, 0x0000);
temp = star_mdc_mdio_read(sdev, star_prv->phy_addr, 24);
star_mdc_mdio_write(sdev, star_prv->phy_addr, 24, temp & (~(1 << 15)));
star_mdc_mdio_write(sdev, star_prv->phy_addr, 31, save_page);
#endif
#if 0
/* init tx for realtek RMII timing issue */
temp = star_get_reg(star_test0(sdev->base));
temp &= ~(0x1 << 31);
/* select tx clock inverse */
temp |= (0x1 << 31);
star_set_reg(star_test0(sdev->base), temp);
STAR_MSG(STAR_DBG, "0x58(0x%x).\n",
star_get_reg(star_test0(sdev->base)));
#endif
}
void rtl8201fr_wol_enable(struct net_device *netdev)
{
star_private *star_prv = NULL;
star_dev *dev = NULL;
struct sockaddr sa;
char *mac_addr = sa.sa_data;
u32 val = 0;
star_prv = netdev_priv(netdev);
dev = &star_prv->star_dev;
STAR_MSG(STAR_DBG, "enter rtl8201fr_wol_enable\n");
memcpy(sa.sa_data, netdev->dev_addr, netdev->addr_len);
STAR_MSG(STAR_DBG, "device mac address:%x %x %x %x %x %x.\n",
netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
/* enable phy wol */
star_mdc_mdio_write(dev, star_prv->phy_addr, 4, 0x61);
star_mdc_mdio_write(dev, star_prv->phy_addr, 0, 0x3200);
/* set mac address */
star_mdc_mdio_write(dev, star_prv->phy_addr, 31, 0x12);
star_mdc_mdio_write(dev, star_prv->phy_addr, 16,
(mac_addr[1] << 8) | (mac_addr[0] << 0));
star_mdc_mdio_write(dev, star_prv->phy_addr, 17,
(mac_addr[3] << 8) | (mac_addr[2] << 0));
star_mdc_mdio_write(dev, star_prv->phy_addr, 18,
(mac_addr[5] << 8) | (mac_addr[4] << 0));
STAR_MSG(STAR_DBG, "mac address:%x %x %x %x %x %x.\n",
mac_addr[0], mac_addr[1], mac_addr[2],
mac_addr[3], mac_addr[4], mac_addr[5]);
/* set max length */
star_mdc_mdio_write(dev, star_prv->phy_addr, 31, 0x11);
star_mdc_mdio_write(dev, star_prv->phy_addr, 17, 0x1FFF);
/* enable magic packet event */
star_mdc_mdio_write(dev, star_prv->phy_addr, 16, 0x1000);
/* set tx isolate */
star_mdc_mdio_write(dev, star_prv->phy_addr, 31, 0x7);
val = star_mdc_mdio_read(dev, star_prv->phy_addr, 20);
star_mdc_mdio_write(dev, star_prv->phy_addr, 20, val | (1 << 15));
/* set rx isolate */
star_mdc_mdio_write(dev, star_prv->phy_addr, 31, 0x17);
val = star_mdc_mdio_read(dev, star_prv->phy_addr, 19);
star_mdc_mdio_write(dev, star_prv->phy_addr, 19, val | (1 << 15));
/* return page 0 */
star_mdc_mdio_write(dev, star_prv->phy_addr, 31, 0);
}
void rtl8201fr_wol_disable(struct net_device *netdev)
{
u32 val = 0;
star_private *star_prv = netdev_priv(netdev);
star_dev *dev = &star_prv->star_dev;
STAR_MSG(STAR_DBG, "enter rtl8201fr_wol_disable\n");
/* unset rx isolate */
star_mdc_mdio_write(dev, star_prv->phy_addr, 31, 0x17);
val = star_mdc_mdio_read(dev, star_prv->phy_addr, 19);
star_mdc_mdio_write(dev, star_prv->phy_addr, 19, val & (~(1 << 15)));
/* unset tx isolate */
star_mdc_mdio_write(dev, star_prv->phy_addr, 31, 0x7);
val = star_mdc_mdio_read(dev, star_prv->phy_addr, 20);
star_mdc_mdio_write(dev, star_prv->phy_addr, 20, val & (~(1 << 15)));
star_mdc_mdio_write(dev, star_prv->phy_addr, 31, 0x11);
/* disable magic packet event */
star_mdc_mdio_write(dev, star_prv->phy_addr, 16, 0x0);
/* unset max length and reset PMEB pin as high */
star_mdc_mdio_write(dev, star_prv->phy_addr, 17, 0x9FFF);
/* return page 0 */
star_mdc_mdio_write(dev, star_prv->phy_addr, 31, 0);
}
static struct eth_phy_ops rtl8201fr_phy_ops = {
.phy_id = PHYID2_RTL8201FR,
.init = rtl8201fr_phy_init,
.wol_enable = rtl8201fr_wol_enable,
.wol_disable = rtl8201fr_wol_disable,
};
int star_detect_phyid(star_dev *dev)
{
int addr;
u16 reg2;
for (addr = 0; addr < 32; addr++) {
reg2 = star_mdc_mdio_read(dev, addr, PHY_REG_IDENTFIR2);
STAR_MSG(STAR_DBG, "%s(%d) id=%d, vendor=0x%x\n",
__func__, __LINE__, addr, reg2);
if (reg2 == PHYID2_SMSC8710A) {
STAR_MSG(STAR_WARN, "Ethernet: SMSC8710A PHY\n\r");
dev->phy_ops = &smsc8710a_phy_ops;
dev->phy_ops->addr = addr;
break;
} else if (reg2 == PHYID2_DM9162_XMII) {
STAR_MSG(STAR_WARN, "Ethernet: DM9162 PHY\n\r");
dev->phy_ops = &dm9162_phy_ops;
dev->phy_ops->addr = addr;
break;
} else if (reg2 == PHYID2_KSZ8081MNX) {
STAR_MSG(STAR_WARN, "Ethernet: KSZ8081 PHY\n\r");
dev->phy_ops = &ksz8081mnx_phy_ops;
dev->phy_ops->addr = addr;
break;
} else if (reg2 == PHYID2_IP101G) {
STAR_MSG(STAR_WARN, "Ethernet: IP101G PHY\n\r");
dev->phy_ops = &ip101g_phy_ops;
dev->phy_ops->addr = addr;
break;
} else if (reg2 == PHYID2_RTL8201FR) {
STAR_MSG(STAR_WARN, "Ethernet: RTL8201FR PHY\n\r");
dev->phy_ops = &rtl8201fr_phy_ops;
dev->phy_ops->addr = addr;
break;
}
}
if (addr == 32) {
for (addr = 0; addr < 32; addr++) {
reg2 = star_mdc_mdio_read(dev, addr, PHY_REG_IDENTFIR2);
STAR_MSG(STAR_ERR,
"%s id=%d, vendor=0x%x\n", __func__,
addr, reg2);
if (reg2 != 0xFFFF) {
STAR_MSG(STAR_ERR,
"Don't support current PHY\n");
dev->phy_ops = &default_phy_ops;
dev->phy_ops->phy_id = reg2;
dev->phy_ops->addr = addr;
break;
}
}
}
return addr;
}