6db4831e98
Android 14
632 lines
16 KiB
C
632 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2018 MediaTek Inc.
|
|
* Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/delay.h>
|
|
|
|
#include "mt753x.h"
|
|
#include "mt753x_regs.h"
|
|
|
|
/* MT7530 registers */
|
|
|
|
/* Unique fields of PMCR for MT7530 */
|
|
#define FORCE_MODE BIT(15)
|
|
|
|
/* Unique fields of GMACCR for MT7530 */
|
|
#define VLAN_SUPT_NO_S 14
|
|
#define VLAN_SUPT_NO_M 0x1c000
|
|
#define LATE_COL_DROP BIT(13)
|
|
|
|
/* Unique fields of (M)HWSTRAP for MT7530 */
|
|
#define BOND_OPTION BIT(24)
|
|
#define P5_PHY0_SEL BIT(20)
|
|
#define CHG_TRAP BIT(16)
|
|
#define LOOPDET_DIS BIT(14)
|
|
#define P5_INTF_SEL_GMAC5 BIT(13)
|
|
#define SMI_ADDR_S 11
|
|
#define SMI_ADDR_M 0x1800
|
|
#define XTAL_FSEL_S 9
|
|
#define XTAL_FSEL_M 0x600
|
|
#define P6_INTF_DIS BIT(8)
|
|
#define P5_INTF_MODE_RGMII BIT(7)
|
|
#define P5_INTF_DIS_S BIT(6)
|
|
#define C_MDIO_BPS_S BIT(5)
|
|
#define EEPROM_EN_S BIT(4)
|
|
|
|
/* PHY EEE Register bitmap of define */
|
|
#define PHY_DEV07 0x07
|
|
#define PHY_DEV07_REG_03C 0x3c
|
|
|
|
/* PHY Extend Register 0x14 bitmap of define */
|
|
#define PHY_EXT_REG_14 0x14
|
|
|
|
/* Fields of PHY_EXT_REG_14 */
|
|
#define PHY_EN_DOWN_SHFIT BIT(4)
|
|
|
|
/* PHY Token Ring Register 0x10 bitmap of define */
|
|
#define PHY_TR_REG_10 0x10
|
|
|
|
/* PHY Token Ring Register 0x12 bitmap of define */
|
|
#define PHY_TR_REG_12 0x12
|
|
|
|
/* PHY LPI PCS/DSP Control Register bitmap of define */
|
|
#define PHY_LPI_REG_11 0x11
|
|
|
|
/* PHY DEV 0x1e Register bitmap of define */
|
|
#define PHY_DEV1E 0x1e
|
|
#define PHY_DEV1E_REG_123 0x123
|
|
#define PHY_DEV1E_REG_A6 0xa6
|
|
|
|
/* Values of XTAL_FSEL */
|
|
#define XTAL_20MHZ 1
|
|
#define XTAL_40MHZ 2
|
|
#define XTAL_25MHZ 3
|
|
|
|
#define P6ECR 0x7830
|
|
#define P6_INTF_MODE_TRGMII BIT(0)
|
|
|
|
#define TRGMII_TXCTRL 0x7a40
|
|
#define TRAIN_TXEN BIT(31)
|
|
#define TXC_INV BIT(30)
|
|
#define TX_DOEO BIT(29)
|
|
#define TX_RST BIT(28)
|
|
|
|
#define TRGMII_TD0_CTRL 0x7a50
|
|
#define TRGMII_TD1_CTRL 0x7a58
|
|
#define TRGMII_TD2_CTRL 0x7a60
|
|
#define TRGMII_TD3_CTRL 0x7a68
|
|
#define TRGMII_TXCTL_CTRL 0x7a70
|
|
#define TRGMII_TCK_CTRL 0x7a78
|
|
#define TRGMII_TD_CTRL(n) (0x7a50 + (n) * 8)
|
|
#define NUM_TRGMII_CTRL 6
|
|
#define TX_DMPEDRV BIT(31)
|
|
#define TX_DM_SR BIT(15)
|
|
#define TX_DMERODT BIT(14)
|
|
#define TX_DMOECTL BIT(13)
|
|
#define TX_TAP_S 8
|
|
#define TX_TAP_M 0xf00
|
|
#define TX_TRAIN_WD_S 0
|
|
#define TX_TRAIN_WD_M 0xff
|
|
|
|
#define TRGMII_TD0_ODT 0x7a54
|
|
#define TRGMII_TD1_ODT 0x7a5c
|
|
#define TRGMII_TD2_ODT 0x7a64
|
|
#define TRGMII_TD3_ODT 0x7a6c
|
|
#define TRGMII_TXCTL_ODT 0x7574
|
|
#define TRGMII_TCK_ODT 0x757c
|
|
#define TRGMII_TD_ODT(n) (0x7a54 + (n) * 8)
|
|
#define NUM_TRGMII_ODT 6
|
|
#define TX_DM_DRVN_PRE_S 30
|
|
#define TX_DM_DRVN_PRE_M 0xc0000000
|
|
#define TX_DM_DRVP_PRE_S 28
|
|
#define TX_DM_DRVP_PRE_M 0x30000000
|
|
#define TX_DM_TDSEL_S 24
|
|
#define TX_DM_TDSEL_M 0xf000000
|
|
#define TX_ODTEN BIT(23)
|
|
#define TX_DME_PRE BIT(20)
|
|
#define TX_DM_DRVNT0 BIT(19)
|
|
#define TX_DM_DRVPT0 BIT(18)
|
|
#define TX_DM_DRVNTE BIT(17)
|
|
#define TX_DM_DRVPTE BIT(16)
|
|
#define TX_DM_ODTN_S 12
|
|
#define TX_DM_ODTN_M 0x7000
|
|
#define TX_DM_ODTP_S 8
|
|
#define TX_DM_ODTP_M 0x700
|
|
#define TX_DM_DRVN_S 4
|
|
#define TX_DM_DRVN_M 0xf0
|
|
#define TX_DM_DRVP_S 0
|
|
#define TX_DM_DRVP_M 0x0f
|
|
|
|
#define P5RGMIIRXCR 0x7b00
|
|
#define CSR_RGMII_RCTL_CFG_S 24
|
|
#define CSR_RGMII_RCTL_CFG_M 0x7000000
|
|
#define CSR_RGMII_RXD_CFG_S 16
|
|
#define CSR_RGMII_RXD_CFG_M 0x70000
|
|
#define CSR_RGMII_EDGE_ALIGN BIT(8)
|
|
#define CSR_RGMII_RXC_90DEG_CFG_S 4
|
|
#define CSR_RGMII_RXC_90DEG_CFG_M 0xf0
|
|
#define CSR_RGMII_RXC_0DEG_CFG_S 0
|
|
#define CSR_RGMII_RXC_0DEG_CFG_M 0x0f
|
|
|
|
#define P5RGMIITXCR 0x7b04
|
|
#define CSR_RGMII_TXEN_CFG_S 16
|
|
#define CSR_RGMII_TXEN_CFG_M 0x70000
|
|
#define CSR_RGMII_TXD_CFG_S 8
|
|
#define CSR_RGMII_TXD_CFG_M 0x700
|
|
#define CSR_RGMII_TXC_CFG_S 0
|
|
#define CSR_RGMII_TXC_CFG_M 0x1f
|
|
|
|
#define CHIP_REV 0x7ffc
|
|
#define CHIP_NAME_S 16
|
|
#define CHIP_NAME_M 0xffff0000
|
|
#define CHIP_REV_S 0
|
|
#define CHIP_REV_M 0x0f
|
|
|
|
/* MMD registers */
|
|
#define CORE_PLL_GROUP2 0x401
|
|
#define RG_SYSPLL_EN_NORMAL BIT(15)
|
|
#define RG_SYSPLL_VODEN BIT(14)
|
|
#define RG_SYSPLL_POSDIV_S 5
|
|
#define RG_SYSPLL_POSDIV_M 0x60
|
|
|
|
#define CORE_PLL_GROUP4 0x403
|
|
#define RG_SYSPLL_DDSFBK_EN BIT(12)
|
|
#define RG_SYSPLL_BIAS_EN BIT(11)
|
|
#define RG_SYSPLL_BIAS_LPF_EN BIT(10)
|
|
|
|
#define CORE_PLL_GROUP5 0x404
|
|
#define RG_LCDDS_PCW_NCPO1_S 0
|
|
#define RG_LCDDS_PCW_NCPO1_M 0xffff
|
|
|
|
#define CORE_PLL_GROUP6 0x405
|
|
#define RG_LCDDS_PCW_NCPO0_S 0
|
|
#define RG_LCDDS_PCW_NCPO0_M 0xffff
|
|
|
|
#define CORE_PLL_GROUP7 0x406
|
|
#define RG_LCDDS_PWDB BIT(15)
|
|
#define RG_LCDDS_ISO_EN BIT(13)
|
|
#define RG_LCCDS_C_S 4
|
|
#define RG_LCCDS_C_M 0x70
|
|
#define RG_LCDDS_PCW_NCPO_CHG BIT(3)
|
|
|
|
#define CORE_PLL_GROUP10 0x409
|
|
#define RG_LCDDS_SSC_DELTA_S 0
|
|
#define RG_LCDDS_SSC_DELTA_M 0xfff
|
|
|
|
#define CORE_PLL_GROUP11 0x40a
|
|
#define RG_LCDDS_SSC_DELTA1_S 0
|
|
#define RG_LCDDS_SSC_DELTA1_M 0xfff
|
|
|
|
#define CORE_GSWPLL_GCR_1 0x040d
|
|
#define GSWPLL_PREDIV_S 14
|
|
#define GSWPLL_PREDIV_M 0xc000
|
|
#define GSWPLL_POSTDIV_200M_S 12
|
|
#define GSWPLL_POSTDIV_200M_M 0x3000
|
|
#define GSWPLL_EN_PRE BIT(11)
|
|
#define GSWPLL_FBKSEL BIT(10)
|
|
#define GSWPLL_BP BIT(9)
|
|
#define GSWPLL_BR BIT(8)
|
|
#define GSWPLL_FBKDIV_200M_S 0
|
|
#define GSWPLL_FBKDIV_200M_M 0xff
|
|
|
|
#define CORE_GSWPLL_GCR_2 0x040e
|
|
#define GSWPLL_POSTDIV_500M_S 8
|
|
#define GSWPLL_POSTDIV_500M_M 0x300
|
|
#define GSWPLL_FBKDIV_500M_S 0
|
|
#define GSWPLL_FBKDIV_500M_M 0xff
|
|
|
|
#define TRGMII_GSW_CLK_CG 0x0410
|
|
#define TRGMIICK_EN BIT(1)
|
|
#define GSWCK_EN BIT(0)
|
|
|
|
static int mt7530_mii_read(struct gsw_mt753x *gsw, int phy, int reg)
|
|
{
|
|
if (phy < MT753X_NUM_PHYS)
|
|
phy = (gsw->phy_base + phy) & MT753X_SMI_ADDR_MASK;
|
|
|
|
return mdiobus_read(gsw->host_bus, phy, reg);
|
|
}
|
|
|
|
static void mt7530_mii_write(struct gsw_mt753x *gsw, int phy, int reg, u16 val)
|
|
{
|
|
if (phy < MT753X_NUM_PHYS)
|
|
phy = (gsw->phy_base + phy) & MT753X_SMI_ADDR_MASK;
|
|
|
|
mdiobus_write(gsw->host_bus, phy, reg, val);
|
|
}
|
|
|
|
static int mt7530_mmd_read(struct gsw_mt753x *gsw, int addr, int devad, u16 reg)
|
|
{
|
|
u16 val;
|
|
|
|
if (addr < MT753X_NUM_PHYS)
|
|
addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK;
|
|
|
|
mutex_lock(&gsw->host_bus->mdio_lock);
|
|
|
|
gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG,
|
|
(MMD_ADDR << MMD_CMD_S) |
|
|
((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
|
|
gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG, reg);
|
|
|
|
gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG,
|
|
(MMD_DATA << MMD_CMD_S) |
|
|
((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
|
|
val = gsw->host_bus->read(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG);
|
|
|
|
mutex_unlock(&gsw->host_bus->mdio_lock);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void mt7530_mmd_write(struct gsw_mt753x *gsw, int addr, int devad,
|
|
u16 reg, u16 val)
|
|
{
|
|
if (addr < MT753X_NUM_PHYS)
|
|
addr = (gsw->phy_base + addr) & MT753X_SMI_ADDR_MASK;
|
|
|
|
mutex_lock(&gsw->host_bus->mdio_lock);
|
|
|
|
gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG,
|
|
(MMD_ADDR << MMD_CMD_S) |
|
|
((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
|
|
gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG, reg);
|
|
|
|
gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ACC_CTL_REG,
|
|
(MMD_DATA << MMD_CMD_S) |
|
|
((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
|
|
gsw->host_bus->write(gsw->host_bus, addr, MII_MMD_ADDR_DATA_REG, val);
|
|
|
|
mutex_unlock(&gsw->host_bus->mdio_lock);
|
|
}
|
|
|
|
static void mt7530_core_reg_write(struct gsw_mt753x *gsw, u32 reg, u32 val)
|
|
{
|
|
gsw->mmd_write(gsw, 0, 0x1f, reg, val);
|
|
}
|
|
|
|
static void mt7530_trgmii_setting(struct gsw_mt753x *gsw)
|
|
{
|
|
u16 i;
|
|
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP5, 0x0780);
|
|
mdelay(1);
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP6, 0);
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP10, 0x87);
|
|
mdelay(1);
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP11, 0x87);
|
|
|
|
/* PLL BIAS enable */
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP4,
|
|
RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN);
|
|
mdelay(1);
|
|
|
|
/* PLL LPF enable */
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP4,
|
|
RG_SYSPLL_DDSFBK_EN |
|
|
RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
|
|
|
|
/* sys PLL enable */
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP2,
|
|
RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
|
|
(1 << RG_SYSPLL_POSDIV_S));
|
|
|
|
/* LCDDDS PWDS */
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP7,
|
|
(3 << RG_LCCDS_C_S) |
|
|
RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
|
|
mdelay(1);
|
|
|
|
/* Enable MT7530 TRGMII clock */
|
|
mt7530_core_reg_write(gsw, TRGMII_GSW_CLK_CG, GSWCK_EN | TRGMIICK_EN);
|
|
|
|
/* lower Tx Driving */
|
|
for (i = 0 ; i < NUM_TRGMII_ODT; i++)
|
|
mt753x_reg_write(gsw, TRGMII_TD_ODT(i),
|
|
(4 << TX_DM_DRVP_S) | (4 << TX_DM_DRVN_S));
|
|
}
|
|
|
|
static void mt7530_rgmii_setting(struct gsw_mt753x *gsw)
|
|
{
|
|
u32 val;
|
|
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP5, 0x0c80);
|
|
mdelay(1);
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP6, 0);
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP10, 0x87);
|
|
mdelay(1);
|
|
mt7530_core_reg_write(gsw, CORE_PLL_GROUP11, 0x87);
|
|
|
|
val = mt753x_reg_read(gsw, TRGMII_TXCTRL);
|
|
val &= ~TXC_INV;
|
|
mt753x_reg_write(gsw, TRGMII_TXCTRL, val);
|
|
|
|
mt753x_reg_write(gsw, TRGMII_TCK_CTRL,
|
|
(8 << TX_TAP_S) | (0x55 << TX_TRAIN_WD_S));
|
|
}
|
|
|
|
static int mt7530_mac_port_setup(struct gsw_mt753x *gsw)
|
|
{
|
|
u32 hwstrap, p6ecr = 0, p5mcr, p6mcr, phyad;
|
|
|
|
hwstrap = mt753x_reg_read(gsw, MHWSTRAP);
|
|
hwstrap &= ~(P6_INTF_DIS | P5_INTF_MODE_RGMII | P5_INTF_DIS_S);
|
|
hwstrap |= P5_INTF_SEL_GMAC5;
|
|
if (!gsw->port5_cfg.enabled) {
|
|
p5mcr = FORCE_MODE;
|
|
hwstrap |= P5_INTF_DIS_S;
|
|
} else {
|
|
p5mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
MAC_MODE | MAC_TX_EN | MAC_RX_EN |
|
|
BKOFF_EN | BACKPR_EN;
|
|
|
|
if (gsw->port5_cfg.force_link) {
|
|
p5mcr |= FORCE_MODE | FORCE_LINK | FORCE_RX_FC |
|
|
FORCE_TX_FC;
|
|
p5mcr |= gsw->port5_cfg.speed << FORCE_SPD_S;
|
|
|
|
if (gsw->port5_cfg.duplex)
|
|
p5mcr |= FORCE_DPX;
|
|
}
|
|
|
|
switch (gsw->port5_cfg.phy_mode) {
|
|
case PHY_INTERFACE_MODE_MII:
|
|
case PHY_INTERFACE_MODE_GMII:
|
|
break;
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
hwstrap |= P5_INTF_MODE_RGMII;
|
|
break;
|
|
default:
|
|
dev_info(gsw->dev, "%s is not supported by port5\n",
|
|
phy_modes(gsw->port5_cfg.phy_mode));
|
|
p5mcr = FORCE_MODE;
|
|
hwstrap |= P5_INTF_DIS_S;
|
|
}
|
|
|
|
/* Port5 to PHY direct mode */
|
|
if (of_property_read_u32(gsw->port5_cfg.np, "phy-address",
|
|
&phyad))
|
|
goto parse_p6;
|
|
|
|
if (phyad != 0 && phyad != 4) {
|
|
dev_info(gsw->dev,
|
|
"Only PHY 0/4 can be connected to Port 5\n");
|
|
goto parse_p6;
|
|
}
|
|
|
|
hwstrap &= ~P5_INTF_SEL_GMAC5;
|
|
if (phyad == 0)
|
|
hwstrap |= P5_PHY0_SEL;
|
|
else
|
|
hwstrap &= ~P5_PHY0_SEL;
|
|
}
|
|
|
|
parse_p6:
|
|
if (!gsw->port6_cfg.enabled) {
|
|
p6mcr = FORCE_MODE;
|
|
hwstrap |= P6_INTF_DIS;
|
|
} else {
|
|
p6mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
MAC_MODE | MAC_TX_EN | MAC_RX_EN |
|
|
BKOFF_EN | BACKPR_EN;
|
|
|
|
if (gsw->port6_cfg.force_link) {
|
|
p6mcr |= FORCE_MODE | FORCE_LINK | FORCE_RX_FC |
|
|
FORCE_TX_FC;
|
|
p6mcr |= gsw->port6_cfg.speed << FORCE_SPD_S;
|
|
|
|
if (gsw->port6_cfg.duplex)
|
|
p6mcr |= FORCE_DPX;
|
|
}
|
|
|
|
switch (gsw->port6_cfg.phy_mode) {
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
p6ecr = BIT(1);
|
|
break;
|
|
case PHY_INTERFACE_MODE_TRGMII:
|
|
/* set MT7530 central align */
|
|
p6ecr = BIT(0);
|
|
break;
|
|
default:
|
|
dev_info(gsw->dev, "%s is not supported by port6\n",
|
|
phy_modes(gsw->port6_cfg.phy_mode));
|
|
p6mcr = FORCE_MODE;
|
|
hwstrap |= P6_INTF_DIS;
|
|
}
|
|
}
|
|
|
|
mt753x_reg_write(gsw, MHWSTRAP, hwstrap);
|
|
mt753x_reg_write(gsw, P6ECR, p6ecr);
|
|
|
|
mt753x_reg_write(gsw, PMCR(5), p5mcr);
|
|
mt753x_reg_write(gsw, PMCR(6), p6mcr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void mt7530_core_pll_setup(struct gsw_mt753x *gsw)
|
|
{
|
|
u32 hwstrap;
|
|
|
|
hwstrap = mt753x_reg_read(gsw, HWSTRAP);
|
|
|
|
switch ((hwstrap & XTAL_FSEL_M) >> XTAL_FSEL_S) {
|
|
case XTAL_40MHZ:
|
|
/* Disable MT7530 core clock */
|
|
mt7530_core_reg_write(gsw, TRGMII_GSW_CLK_CG, 0);
|
|
|
|
/* disable MT7530 PLL */
|
|
mt7530_core_reg_write(gsw, CORE_GSWPLL_GCR_1,
|
|
(2 << GSWPLL_POSTDIV_200M_S) |
|
|
(32 << GSWPLL_FBKDIV_200M_S));
|
|
|
|
/* For MT7530 core clock = 500Mhz */
|
|
mt7530_core_reg_write(gsw, CORE_GSWPLL_GCR_2,
|
|
(1 << GSWPLL_POSTDIV_500M_S) |
|
|
(25 << GSWPLL_FBKDIV_500M_S));
|
|
|
|
/* Enable MT7530 PLL */
|
|
mt7530_core_reg_write(gsw, CORE_GSWPLL_GCR_1,
|
|
(2 << GSWPLL_POSTDIV_200M_S) |
|
|
(32 << GSWPLL_FBKDIV_200M_S) |
|
|
GSWPLL_EN_PRE);
|
|
|
|
usleep_range(20, 40);
|
|
|
|
/* Enable MT7530 core clock */
|
|
mt7530_core_reg_write(gsw, TRGMII_GSW_CLK_CG, GSWCK_EN);
|
|
break;
|
|
default:
|
|
/* TODO: PLL settings for 20/25MHz */
|
|
break;
|
|
}
|
|
|
|
hwstrap = mt753x_reg_read(gsw, HWSTRAP);
|
|
hwstrap |= CHG_TRAP;
|
|
if (gsw->direct_phy_access)
|
|
hwstrap &= ~C_MDIO_BPS_S;
|
|
else
|
|
hwstrap |= C_MDIO_BPS_S;
|
|
|
|
mt753x_reg_write(gsw, MHWSTRAP, hwstrap);
|
|
|
|
if (gsw->port6_cfg.enabled &&
|
|
gsw->port6_cfg.phy_mode == PHY_INTERFACE_MODE_TRGMII) {
|
|
mt7530_trgmii_setting(gsw);
|
|
} else {
|
|
/* RGMII */
|
|
mt7530_rgmii_setting(gsw);
|
|
}
|
|
|
|
/* delay setting for 10/1000M */
|
|
mt753x_reg_write(gsw, P5RGMIIRXCR,
|
|
CSR_RGMII_EDGE_ALIGN |
|
|
(2 << CSR_RGMII_RXC_0DEG_CFG_S));
|
|
mt753x_reg_write(gsw, P5RGMIITXCR, 0x14 << CSR_RGMII_TXC_CFG_S);
|
|
}
|
|
|
|
static int mt7530_sw_detect(struct gsw_mt753x *gsw, struct chip_rev *crev)
|
|
{
|
|
u32 rev;
|
|
|
|
rev = mt753x_reg_read(gsw, CHIP_REV);
|
|
|
|
if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == MT7530) {
|
|
if (crev) {
|
|
crev->rev = rev & CHIP_REV_M;
|
|
crev->name = "MT7530";
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
return -ENODEV;
|
|
}
|
|
|
|
static void mt7530_phy_setting(struct gsw_mt753x *gsw)
|
|
{
|
|
int i;
|
|
u32 val;
|
|
|
|
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
/* Disable EEE */
|
|
gsw->mmd_write(gsw, i, PHY_DEV07, PHY_DEV07_REG_03C, 0);
|
|
|
|
/* Enable HW auto downshift */
|
|
gsw->mii_write(gsw, i, 0x1f, 0x1);
|
|
val = gsw->mii_read(gsw, i, PHY_EXT_REG_14);
|
|
val |= PHY_EN_DOWN_SHFIT;
|
|
gsw->mii_write(gsw, i, PHY_EXT_REG_14, val);
|
|
|
|
/* Increase SlvDPSready time */
|
|
gsw->mii_write(gsw, i, 0x1f, 0x52b5);
|
|
gsw->mii_write(gsw, i, PHY_TR_REG_10, 0xafae);
|
|
gsw->mii_write(gsw, i, PHY_TR_REG_12, 0x2f);
|
|
gsw->mii_write(gsw, i, PHY_TR_REG_10, 0x8fae);
|
|
|
|
/* Increase post_update_timer */
|
|
gsw->mii_write(gsw, i, 0x1f, 0x3);
|
|
gsw->mii_write(gsw, i, PHY_LPI_REG_11, 0x4b);
|
|
gsw->mii_write(gsw, i, 0x1f, 0);
|
|
|
|
/* Adjust 100_mse_threshold */
|
|
gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_123, 0xffff);
|
|
|
|
/* Disable mcc */
|
|
gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_A6, 0x300);
|
|
}
|
|
}
|
|
|
|
static inline bool get_phy_access_mode(const struct device_node *np)
|
|
{
|
|
return of_property_read_bool(np, "mt7530,direct-phy-access");
|
|
}
|
|
|
|
static int mt7530_sw_init(struct gsw_mt753x *gsw)
|
|
{
|
|
int i;
|
|
u32 val;
|
|
|
|
gsw->direct_phy_access = get_phy_access_mode(gsw->dev->of_node);
|
|
|
|
/* Force MT7530 to use (in)direct PHY access */
|
|
val = mt753x_reg_read(gsw, HWSTRAP);
|
|
val |= CHG_TRAP;
|
|
if (gsw->direct_phy_access)
|
|
val &= ~C_MDIO_BPS_S;
|
|
else
|
|
val |= C_MDIO_BPS_S;
|
|
mt753x_reg_write(gsw, MHWSTRAP, val);
|
|
|
|
/* Read PHY address base from HWSTRAP */
|
|
gsw->phy_base = (((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3) + 8;
|
|
gsw->phy_base &= MT753X_SMI_ADDR_MASK;
|
|
|
|
if (gsw->direct_phy_access) {
|
|
gsw->mii_read = mt7530_mii_read;
|
|
gsw->mii_write = mt7530_mii_write;
|
|
gsw->mmd_read = mt7530_mmd_read;
|
|
gsw->mmd_write = mt7530_mmd_write;
|
|
} else {
|
|
gsw->mii_read = mt753x_mii_read;
|
|
gsw->mii_write = mt753x_mii_write;
|
|
gsw->mmd_read = mt753x_mmd_ind_read;
|
|
gsw->mmd_write = mt753x_mmd_ind_write;
|
|
}
|
|
|
|
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
val = gsw->mii_read(gsw, i, MII_BMCR);
|
|
val |= BMCR_PDOWN;
|
|
gsw->mii_write(gsw, i, MII_BMCR, val);
|
|
}
|
|
|
|
/* Force MAC link down before reset */
|
|
mt753x_reg_write(gsw, PMCR(5), FORCE_MODE);
|
|
mt753x_reg_write(gsw, PMCR(6), FORCE_MODE);
|
|
|
|
/* Switch soft reset */
|
|
/* BUG: sw reset causes gsw int flooding */
|
|
mt753x_reg_write(gsw, SYS_CTRL, SW_PHY_RST | SW_SYS_RST | SW_REG_RST);
|
|
usleep_range(10, 20);
|
|
|
|
/* global mac control settings configuration */
|
|
mt753x_reg_write(gsw, GMACCR,
|
|
LATE_COL_DROP | (15 << MTCC_LMT_S) |
|
|
(2 << MAX_RX_JUMBO_S) | RX_PKT_LEN_MAX_JUMBO);
|
|
|
|
mt7530_core_pll_setup(gsw);
|
|
mt7530_mac_port_setup(gsw);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mt7530_sw_post_init(struct gsw_mt753x *gsw)
|
|
{
|
|
int i;
|
|
u32 val;
|
|
|
|
mt7530_phy_setting(gsw);
|
|
|
|
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
val = gsw->mii_read(gsw, i, MII_BMCR);
|
|
val &= ~BMCR_PDOWN;
|
|
gsw->mii_write(gsw, i, MII_BMCR, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct mt753x_sw_id mt7530_id = {
|
|
.model = MT7530,
|
|
.detect = mt7530_sw_detect,
|
|
.init = mt7530_sw_init,
|
|
.post_init = mt7530_sw_post_init
|
|
};
|