^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * PHY drivers for the sungem ethernet driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This file could be shared with other drivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * TODO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * - Add support for PHYs that provide an IRQ line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * - Eventually moved the entire polling state machine in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * there (out of the eth driver), so that it can easily be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * skipped on PHYs that implement it in hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * - On LXT971 & BCM5201, Apple uses some chip specific regs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * to read the link status. Figure out why and if it makes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * sense to do the same (magic aneg ?)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * - Apple has some additional power management code for some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Broadcom PHYs that they "hide" from the OpenSource version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * of darwin, still need to reverse engineer that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/etherdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/mii.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/ethtool.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #ifdef CONFIG_PPC_PMAC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <asm/prom.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/sungem_phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /* Link modes of the BCM5400 PHY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static const int phy_BCM5400_link_table[8][3] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) { 0, 0, 0 }, /* No link */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) { 0, 0, 0 }, /* 10BT Half Duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) { 1, 0, 0 }, /* 10BT Full Duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) { 0, 1, 0 }, /* 100BT Half Duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) { 0, 1, 0 }, /* 100BT Half Duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) { 1, 1, 0 }, /* 100BT Full Duplex*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) { 1, 0, 1 }, /* 1000BT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) { 1, 0, 1 }, /* 1000BT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return phy->mdio_read(phy->dev, id, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) phy->mdio_write(phy->dev, id, reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static inline int sungem_phy_read(struct mii_phy* phy, int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return phy->mdio_read(phy->dev, phy->mii_id, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) phy->mdio_write(phy->dev, phy->mii_id, reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) u16 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) int limit = 10000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) val = __sungem_phy_read(phy, phy_id, MII_BMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) val |= BMCR_RESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) __sungem_phy_write(phy, phy_id, MII_BMCR, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) udelay(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) while (--limit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) val = __sungem_phy_read(phy, phy_id, MII_BMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if ((val & BMCR_RESET) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if ((val & BMCR_ISOLATE) && limit > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) __sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return limit <= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static int bcm5201_init(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int bcm5201_suspend(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static int bcm5221_init(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) data = sungem_phy_read(phy, MII_BCM5221_TEST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) sungem_phy_write(phy, MII_BCM5221_TEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) data | MII_BCM5221_TEST_ENABLE_SHADOWS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) data = sungem_phy_read(phy, MII_BCM5221_TEST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) sungem_phy_write(phy, MII_BCM5221_TEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static int bcm5221_suspend(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) data = sungem_phy_read(phy, MII_BCM5221_TEST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) sungem_phy_write(phy, MII_BCM5221_TEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) data | MII_BCM5221_TEST_ENABLE_SHADOWS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static int bcm5241_init(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) data = sungem_phy_read(phy, MII_BCM5221_TEST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) sungem_phy_write(phy, MII_BCM5221_TEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) data | MII_BCM5221_TEST_ENABLE_SHADOWS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) data = sungem_phy_read(phy, MII_BCM5221_TEST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) sungem_phy_write(phy, MII_BCM5221_TEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static int bcm5241_suspend(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) data = sungem_phy_read(phy, MII_BCM5221_TEST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) sungem_phy_write(phy, MII_BCM5221_TEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) data | MII_BCM5221_TEST_ENABLE_SHADOWS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static int bcm5400_init(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /* Configure for gigabit full duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) udelay(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) /* Reset and configure cascaded 10/100 PHY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) (void)reset_one_mii_phy(phy, 0x1f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) data |= MII_BCM5201_MULTIPHY_SERIALMODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static int bcm5400_suspend(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) static int bcm5401_init(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) int rev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (rev == 0 || rev == 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) /* Some revisions of 5401 appear to need this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * initialisation sequence to disable, according
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) * to OF, "tap power management"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * WARNING ! OF and Darwin don't agree on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * register addresses. OF seem to interpret the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * register numbers below as decimal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * Note: This should (and does) match tg3_init_5401phy_dsp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * in the tg3.c driver. -DaveM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) sungem_phy_write(phy, 0x18, 0x0c20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) sungem_phy_write(phy, 0x17, 0x0012);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) sungem_phy_write(phy, 0x15, 0x1804);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) sungem_phy_write(phy, 0x17, 0x0013);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) sungem_phy_write(phy, 0x15, 0x1204);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) sungem_phy_write(phy, 0x17, 0x8006);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) sungem_phy_write(phy, 0x15, 0x0132);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) sungem_phy_write(phy, 0x17, 0x8006);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) sungem_phy_write(phy, 0x15, 0x0232);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) sungem_phy_write(phy, 0x17, 0x201f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) sungem_phy_write(phy, 0x15, 0x0a20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) /* Configure for gigabit full duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /* Reset and configure cascaded 10/100 PHY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) (void)reset_one_mii_phy(phy, 0x1f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) data |= MII_BCM5201_MULTIPHY_SERIALMODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static int bcm5401_suspend(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static int bcm5411_init(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* Here's some more Apple black magic to setup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * some voltage stuffs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) sungem_phy_write(phy, 0x1c, 0x8c23);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) sungem_phy_write(phy, 0x1c, 0x8ca3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) sungem_phy_write(phy, 0x1c, 0x8c23);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) /* Here, Apple seems to want to reset it, do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) * it as well
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) sungem_phy_write(phy, MII_BMCR, BMCR_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) sungem_phy_write(phy, MII_BMCR, 0x1340);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) /* Reset and configure cascaded 10/100 PHY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) (void)reset_one_mii_phy(phy, 0x1f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) u16 ctl, adv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) phy->autoneg = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) phy->speed = SPEED_10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) phy->duplex = DUPLEX_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) phy->pause = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) phy->advertising = advertise;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* Setup standard advertise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) adv = sungem_phy_read(phy, MII_ADVERTISE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (advertise & ADVERTISED_10baseT_Half)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) adv |= ADVERTISE_10HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (advertise & ADVERTISED_10baseT_Full)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) adv |= ADVERTISE_10FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (advertise & ADVERTISED_100baseT_Half)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) adv |= ADVERTISE_100HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (advertise & ADVERTISED_100baseT_Full)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) adv |= ADVERTISE_100FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) sungem_phy_write(phy, MII_ADVERTISE, adv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /* Start/Restart aneg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) ctl = sungem_phy_read(phy, MII_BMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) sungem_phy_write(phy, MII_BMCR, ctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) u16 ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) phy->autoneg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) phy->speed = speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) phy->duplex = fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) phy->pause = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) ctl = sungem_phy_read(phy, MII_BMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /* First reset the PHY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) /* Select speed & duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) switch(speed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) case SPEED_10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) case SPEED_100:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) ctl |= BMCR_SPEED100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) case SPEED_1000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (fd == DUPLEX_FULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) ctl |= BMCR_FULLDPLX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) sungem_phy_write(phy, MII_BMCR, ctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) static int genmii_poll_link(struct mii_phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) u16 status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) (void)sungem_phy_read(phy, MII_BMSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) status = sungem_phy_read(phy, MII_BMSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if ((status & BMSR_LSTATUS) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static int genmii_read_link(struct mii_phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) u16 lpa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (phy->autoneg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) lpa = sungem_phy_read(phy, MII_LPA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (lpa & (LPA_10FULL | LPA_100FULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) phy->duplex = DUPLEX_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) phy->duplex = DUPLEX_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (lpa & (LPA_100FULL | LPA_100HALF))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) phy->speed = SPEED_100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) phy->speed = SPEED_10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) phy->pause = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) /* On non-aneg, we assume what we put in BMCR is the speed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) * though magic-aneg shouldn't prevent this case from occurring
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) static int generic_suspend(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) static int bcm5421_init(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) unsigned int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) /* Revision 0 of 5421 needs some fixups */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) if (id == 0x002060e0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) /* This is borrowed from MacOS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) sungem_phy_write(phy, 0x18, 0x1007);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) data = sungem_phy_read(phy, 0x18);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) sungem_phy_write(phy, 0x18, data | 0x0400);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) sungem_phy_write(phy, 0x18, 0x0007);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) data = sungem_phy_read(phy, 0x18);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) sungem_phy_write(phy, 0x18, data | 0x0800);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) sungem_phy_write(phy, 0x17, 0x000a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) data = sungem_phy_read(phy, 0x15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) sungem_phy_write(phy, 0x15, data | 0x0200);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) /* Pick up some init code from OF for K2 version */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if ((id & 0xfffffff0) == 0x002062e0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) sungem_phy_write(phy, 4, 0x01e1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) sungem_phy_write(phy, 9, 0x0300);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) /* Check if we can enable automatic low power */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) #ifdef CONFIG_PPC_PMAC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if (phy->platform_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) struct device_node *np = of_get_parent(phy->platform_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) int can_low_power = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) can_low_power = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (can_low_power) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) /* Enable automatic low-power */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) sungem_phy_write(phy, 0x1c, 0x9002);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) sungem_phy_write(phy, 0x1c, 0xa821);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) sungem_phy_write(phy, 0x1c, 0x941d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) #endif /* CONFIG_PPC_PMAC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) u16 ctl, adv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) phy->autoneg = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) phy->speed = SPEED_10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) phy->duplex = DUPLEX_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) phy->pause = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) phy->advertising = advertise;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) /* Setup standard advertise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) adv = sungem_phy_read(phy, MII_ADVERTISE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) if (advertise & ADVERTISED_10baseT_Half)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) adv |= ADVERTISE_10HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (advertise & ADVERTISED_10baseT_Full)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) adv |= ADVERTISE_10FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (advertise & ADVERTISED_100baseT_Half)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) adv |= ADVERTISE_100HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (advertise & ADVERTISED_100baseT_Full)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) adv |= ADVERTISE_100FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (advertise & ADVERTISED_Pause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) adv |= ADVERTISE_PAUSE_CAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (advertise & ADVERTISED_Asym_Pause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) adv |= ADVERTISE_PAUSE_ASYM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) sungem_phy_write(phy, MII_ADVERTISE, adv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) /* Setup 1000BT advertise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) adv = sungem_phy_read(phy, MII_1000BASETCONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (advertise & SUPPORTED_1000baseT_Half)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) if (advertise & SUPPORTED_1000baseT_Full)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) /* Start/Restart aneg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) ctl = sungem_phy_read(phy, MII_BMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) sungem_phy_write(phy, MII_BMCR, ctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) u16 ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) phy->autoneg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) phy->speed = speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) phy->duplex = fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) phy->pause = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) ctl = sungem_phy_read(phy, MII_BMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /* First reset the PHY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) /* Select speed & duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) switch(speed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) case SPEED_10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) case SPEED_100:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) ctl |= BMCR_SPEED100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) case SPEED_1000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) ctl |= BMCR_SPD2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if (fd == DUPLEX_FULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) ctl |= BMCR_FULLDPLX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) // XXX Should we set the sungem to GII now on 1000BT ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) sungem_phy_write(phy, MII_BMCR, ctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) static int bcm54xx_read_link(struct mii_phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) int link_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) u16 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (phy->autoneg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) DUPLEX_FULL : DUPLEX_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) phy->speed = phy_BCM5400_link_table[link_mode][2] ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) SPEED_1000 :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) (phy_BCM5400_link_table[link_mode][1] ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) SPEED_100 : SPEED_10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) val = sungem_phy_read(phy, MII_LPA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) phy->pause = (phy->duplex == DUPLEX_FULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) ((val & LPA_PAUSE) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) /* On non-aneg, we assume what we put in BMCR is the speed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) * though magic-aneg shouldn't prevent this case from occurring
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) static int marvell88e1111_init(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) u16 rev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) /* magic init sequence for rev 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (rev == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) sungem_phy_write(phy, 0x1d, 0x000a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) sungem_phy_write(phy, 0x1e, 0x0821);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) sungem_phy_write(phy, 0x1d, 0x0006);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) sungem_phy_write(phy, 0x1e, 0x8600);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) sungem_phy_write(phy, 0x1d, 0x000b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) sungem_phy_write(phy, 0x1e, 0x0100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) sungem_phy_write(phy, 0x1d, 0x0004);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) sungem_phy_write(phy, 0x1e, 0x4850);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) #define BCM5421_MODE_MASK (1 << 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) static int bcm5421_poll_link(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) u32 phy_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) int mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) /* find out in what mode we are */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) sungem_phy_write(phy, MII_NCONFIG, 0x1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) phy_reg = sungem_phy_read(phy, MII_NCONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if ( mode == BCM54XX_COPPER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) return genmii_poll_link(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) /* try to find out whether we have a link */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) sungem_phy_write(phy, MII_NCONFIG, 0x2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) phy_reg = sungem_phy_read(phy, MII_NCONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) if (phy_reg & 0x0020)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) static int bcm5421_read_link(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) u32 phy_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) int mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) /* find out in what mode we are */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) sungem_phy_write(phy, MII_NCONFIG, 0x1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) phy_reg = sungem_phy_read(phy, MII_NCONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) if ( mode == BCM54XX_COPPER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) return bcm54xx_read_link(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) phy->speed = SPEED_1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) /* find out whether we are running half- or full duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) sungem_phy_write(phy, MII_NCONFIG, 0x2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) phy_reg = sungem_phy_read(phy, MII_NCONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) if ( (phy_reg & 0x0080) >> 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) phy->duplex |= DUPLEX_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) phy->duplex |= DUPLEX_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) /* enable fiber mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) sungem_phy_write(phy, MII_NCONFIG, 0x9020);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) /* LEDs active in both modes, autosense prio = fiber */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) sungem_phy_write(phy, MII_NCONFIG, 0x945f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (!autoneg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) /* switch off fibre autoneg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) sungem_phy_write(phy, 0x0b, 0x0004);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) phy->autoneg = autoneg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) #define BCM5461_FIBER_LINK (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) #define BCM5461_MODE_MASK (3 << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) static int bcm5461_poll_link(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) u32 phy_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) int mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) /* find out in what mode we are */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) phy_reg = sungem_phy_read(phy, MII_NCONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) if ( mode == BCM54XX_COPPER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) return genmii_poll_link(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) /* find out whether we have a link */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) sungem_phy_write(phy, MII_NCONFIG, 0x7000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) phy_reg = sungem_phy_read(phy, MII_NCONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) if (phy_reg & BCM5461_FIBER_LINK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) #define BCM5461_FIBER_DUPLEX (1 << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) static int bcm5461_read_link(struct mii_phy* phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) u32 phy_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) int mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) /* find out in what mode we are */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) phy_reg = sungem_phy_read(phy, MII_NCONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if ( mode == BCM54XX_COPPER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) return bcm54xx_read_link(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) phy->speed = SPEED_1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) /* find out whether we are running half- or full duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) sungem_phy_write(phy, MII_NCONFIG, 0x7000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) phy_reg = sungem_phy_read(phy, MII_NCONFIG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (phy_reg & BCM5461_FIBER_DUPLEX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) phy->duplex |= DUPLEX_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) phy->duplex |= DUPLEX_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) /* select fiber mode, enable 1000 base-X registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) if (autoneg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) /* enable fiber with no autonegotiation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) sungem_phy_write(phy, MII_BMCR, 0x1140);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) /* enable fiber with autonegotiation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) sungem_phy_write(phy, MII_BMCR, 0x0140);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) phy->autoneg = autoneg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) u16 ctl, adv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) phy->autoneg = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) phy->speed = SPEED_10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) phy->duplex = DUPLEX_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) phy->pause = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) phy->advertising = advertise;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) /* Setup standard advertise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) adv = sungem_phy_read(phy, MII_ADVERTISE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) if (advertise & ADVERTISED_10baseT_Half)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) adv |= ADVERTISE_10HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) if (advertise & ADVERTISED_10baseT_Full)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) adv |= ADVERTISE_10FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) if (advertise & ADVERTISED_100baseT_Half)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) adv |= ADVERTISE_100HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) if (advertise & ADVERTISED_100baseT_Full)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) adv |= ADVERTISE_100FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) if (advertise & ADVERTISED_Pause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) adv |= ADVERTISE_PAUSE_CAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) if (advertise & ADVERTISED_Asym_Pause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) adv |= ADVERTISE_PAUSE_ASYM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) sungem_phy_write(phy, MII_ADVERTISE, adv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) /* Setup 1000BT advertise & enable crossover detect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) * XXX How do we advertise 1000BT ? Darwin source is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) * confusing here, they read from specific control and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) * write to control... Someone has specs for those
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) * beasts ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) MII_1000BASETCONTROL_HALFDUPLEXCAP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) if (advertise & SUPPORTED_1000baseT_Half)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) if (advertise & SUPPORTED_1000baseT_Full)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) /* Start/Restart aneg */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) ctl = sungem_phy_read(phy, MII_BMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) sungem_phy_write(phy, MII_BMCR, ctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) u16 ctl, ctl2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) phy->autoneg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) phy->speed = speed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) phy->duplex = fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) phy->pause = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) ctl = sungem_phy_read(phy, MII_BMCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) ctl |= BMCR_RESET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) /* Select speed & duplex */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) switch(speed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) case SPEED_10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) case SPEED_100:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) ctl |= BMCR_SPEED100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) /* I'm not sure about the one below, again, Darwin source is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) * quite confusing and I lack chip specs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) case SPEED_1000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) ctl |= BMCR_SPD2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) if (fd == DUPLEX_FULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) ctl |= BMCR_FULLDPLX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) /* Disable crossover. Again, the way Apple does it is strange,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) * though I don't assume they are wrong ;)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) MII_1000BASETCONTROL_FULLDUPLEXCAP |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) MII_1000BASETCONTROL_HALFDUPLEXCAP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) if (speed == SPEED_1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) ctl2 |= (fd == DUPLEX_FULL) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) MII_1000BASETCONTROL_FULLDUPLEXCAP :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) MII_1000BASETCONTROL_HALFDUPLEXCAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) // XXX Should we set the sungem to GII now on 1000BT ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) sungem_phy_write(phy, MII_BMCR, ctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) static int marvell_read_link(struct mii_phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) u16 status, pmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) if (phy->autoneg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) return -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) if (status & MII_M1011_PHY_SPEC_STATUS_1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) phy->speed = SPEED_1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) else if (status & MII_M1011_PHY_SPEC_STATUS_100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) phy->speed = SPEED_100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) phy->speed = SPEED_10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) phy->duplex = DUPLEX_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) phy->duplex = DUPLEX_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) phy->pause = (status & pmask) == pmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) /* On non-aneg, we assume what we put in BMCR is the speed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) * though magic-aneg shouldn't prevent this case from occurring
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) #define MII_BASIC_FEATURES \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) SUPPORTED_Pause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) /* On gigabit capable PHYs, we advertise Pause support but not asym pause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) * support for now as I'm not sure it's supported and Darwin doesn't do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) * it neither. --BenH.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) #define MII_GBIT_FEATURES \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) (MII_BASIC_FEATURES | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) /* Broadcom BCM 5201 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) static const struct mii_phy_ops bcm5201_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) .init = bcm5201_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) .suspend = bcm5201_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) .setup_aneg = genmii_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) .setup_forced = genmii_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) .read_link = genmii_read_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) static struct mii_phy_def bcm5201_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) .phy_id = 0x00406210,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) .name = "BCM5201",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) .features = MII_BASIC_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) .ops = &bcm5201_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) /* Broadcom BCM 5221 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) static const struct mii_phy_ops bcm5221_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) .suspend = bcm5221_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) .init = bcm5221_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) .setup_aneg = genmii_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) .setup_forced = genmii_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) .read_link = genmii_read_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) static struct mii_phy_def bcm5221_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) .phy_id = 0x004061e0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) .name = "BCM5221",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) .features = MII_BASIC_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) .ops = &bcm5221_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) /* Broadcom BCM 5241 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) static const struct mii_phy_ops bcm5241_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) .suspend = bcm5241_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) .init = bcm5241_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) .setup_aneg = genmii_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) .setup_forced = genmii_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) .read_link = genmii_read_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) static struct mii_phy_def bcm5241_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) .phy_id = 0x0143bc30,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) .name = "BCM5241",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) .features = MII_BASIC_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) .ops = &bcm5241_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) /* Broadcom BCM 5400 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) static const struct mii_phy_ops bcm5400_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) .init = bcm5400_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) .suspend = bcm5400_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) .setup_aneg = bcm54xx_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) .setup_forced = bcm54xx_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) .read_link = bcm54xx_read_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) static struct mii_phy_def bcm5400_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) .phy_id = 0x00206040,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) .name = "BCM5400",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) .features = MII_GBIT_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) .ops = &bcm5400_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) /* Broadcom BCM 5401 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) static const struct mii_phy_ops bcm5401_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) .init = bcm5401_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) .suspend = bcm5401_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) .setup_aneg = bcm54xx_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) .setup_forced = bcm54xx_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) .read_link = bcm54xx_read_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) static struct mii_phy_def bcm5401_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) .phy_id = 0x00206050,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) .name = "BCM5401",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) .features = MII_GBIT_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) .ops = &bcm5401_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) /* Broadcom BCM 5411 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) static const struct mii_phy_ops bcm5411_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) .init = bcm5411_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) .suspend = generic_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) .setup_aneg = bcm54xx_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) .setup_forced = bcm54xx_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) .read_link = bcm54xx_read_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) static struct mii_phy_def bcm5411_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) .phy_id = 0x00206070,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) .name = "BCM5411",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) .features = MII_GBIT_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) .ops = &bcm5411_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) /* Broadcom BCM 5421 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) static const struct mii_phy_ops bcm5421_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) .init = bcm5421_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) .suspend = generic_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) .setup_aneg = bcm54xx_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) .setup_forced = bcm54xx_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) .poll_link = bcm5421_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) .read_link = bcm5421_read_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) .enable_fiber = bcm5421_enable_fiber,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) static struct mii_phy_def bcm5421_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) .phy_id = 0x002060e0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) .name = "BCM5421",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) .features = MII_GBIT_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) .ops = &bcm5421_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) /* Broadcom BCM 5421 built-in K2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) static const struct mii_phy_ops bcm5421k2_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) .init = bcm5421_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) .suspend = generic_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) .setup_aneg = bcm54xx_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) .setup_forced = bcm54xx_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) .read_link = bcm54xx_read_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) static struct mii_phy_def bcm5421k2_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) .phy_id = 0x002062e0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) .name = "BCM5421-K2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) .features = MII_GBIT_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) .ops = &bcm5421k2_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) static const struct mii_phy_ops bcm5461_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) .init = bcm5421_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) .suspend = generic_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) .setup_aneg = bcm54xx_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) .setup_forced = bcm54xx_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) .poll_link = bcm5461_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) .read_link = bcm5461_read_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) .enable_fiber = bcm5461_enable_fiber,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) static struct mii_phy_def bcm5461_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) .phy_id = 0x002060c0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) .name = "BCM5461",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) .features = MII_GBIT_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) .ops = &bcm5461_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) /* Broadcom BCM 5462 built-in Vesta */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) static const struct mii_phy_ops bcm5462V_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) .init = bcm5421_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) .suspend = generic_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) .setup_aneg = bcm54xx_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) .setup_forced = bcm54xx_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) .read_link = bcm54xx_read_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) static struct mii_phy_def bcm5462V_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) .phy_id = 0x002060d0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) .name = "BCM5462-Vesta",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) .features = MII_GBIT_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) .ops = &bcm5462V_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) /* Marvell 88E1101 amd 88E1111 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) static const struct mii_phy_ops marvell88e1101_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) .suspend = generic_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) .setup_aneg = marvell_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) .setup_forced = marvell_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) .read_link = marvell_read_link
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) static const struct mii_phy_ops marvell88e1111_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) .init = marvell88e1111_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) .suspend = generic_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) .setup_aneg = marvell_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) .setup_forced = marvell_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) .read_link = marvell_read_link
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) /* two revs in darwin for the 88e1101 ... I could use a datasheet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) * to get the proper names...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) static struct mii_phy_def marvell88e1101v1_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) .phy_id = 0x01410c20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) .name = "Marvell 88E1101v1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) .features = MII_GBIT_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) .ops = &marvell88e1101_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) static struct mii_phy_def marvell88e1101v2_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) .phy_id = 0x01410c60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) .name = "Marvell 88E1101v2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) .features = MII_GBIT_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) .ops = &marvell88e1101_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) static struct mii_phy_def marvell88e1111_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) .phy_id = 0x01410cc0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) .phy_id_mask = 0xfffffff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) .name = "Marvell 88E1111",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) .features = MII_GBIT_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) .magic_aneg = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) .ops = &marvell88e1111_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) /* Generic implementation for most 10/100 PHYs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) static const struct mii_phy_ops generic_phy_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) .setup_aneg = genmii_setup_aneg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) .setup_forced = genmii_setup_forced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) .poll_link = genmii_poll_link,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) .read_link = genmii_read_link
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) static struct mii_phy_def genmii_phy_def = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) .phy_id = 0x00000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) .phy_id_mask = 0x00000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) .name = "Generic MII",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) .features = MII_BASIC_FEATURES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) .magic_aneg = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) .ops = &generic_phy_ops
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) static struct mii_phy_def* mii_phy_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) &bcm5201_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) &bcm5221_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) &bcm5241_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) &bcm5400_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) &bcm5401_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) &bcm5411_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) &bcm5421_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) &bcm5421k2_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) &bcm5461_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) &bcm5462V_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) &marvell88e1101v1_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) &marvell88e1101v2_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) &marvell88e1111_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) &genmii_phy_def,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) int sungem_phy_probe(struct mii_phy *phy, int mii_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) u32 id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) struct mii_phy_def* def;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) /* We do not reset the mii_phy structure as the driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) * may re-probe the PHY regulary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) phy->mii_id = mii_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) /* Take PHY out of isloate mode and reset it. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) rc = reset_one_mii_phy(phy, mii_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) /* Read ID and find matching entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) id, mii_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) for (i=0; (def = mii_phy_table[i]) != NULL; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) if ((id & def->phy_id_mask) == def->phy_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) /* Should never be NULL (we have a generic entry), but... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) if (def == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) phy->def = def;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) phy->speed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) phy->duplex = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) phy->pause = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) phy->advertising = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) EXPORT_SYMBOL(sungem_phy_probe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) MODULE_LICENSE("GPL");