X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fopenwrt.git;a=blobdiff_plain;f=target%2Flinux%2Fmediatek%2Ffiles-5.10%2Fdrivers%2Fnet%2Fphy%2Fmtk%2Fmt753x%2Fmt7530.c;fp=target%2Flinux%2Fmediatek%2Ffiles-5.10%2Fdrivers%2Fnet%2Fphy%2Fmtk%2Fmt753x%2Fmt7530.c;h=6a94d0d2f4baf4d04bf4455de3a20c4156ca5cf0;hp=0000000000000000000000000000000000000000;hb=c46ccb69d17e584479df849a107423175a143c83;hpb=11425c9de29c8b9c5e4d7eec163a6afbb7fbdce2 diff --git a/target/linux/mediatek/files-5.10/drivers/net/phy/mtk/mt753x/mt7530.c b/target/linux/mediatek/files-5.10/drivers/net/phy/mtk/mt753x/mt7530.c new file mode 100644 index 0000000000..6a94d0d2f4 --- /dev/null +++ b/target/linux/mediatek/files-5.10/drivers/net/phy/mtk/mt753x/mt7530.c @@ -0,0 +1,631 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018 MediaTek Inc. + * Author: Weijie Gao + */ + +#include +#include + +#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 +};