1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 4 #include <linux/mdio.h> 5 #include <linux/pcs/pcs-xpcs.h> 6 7 #include "fbnic.h" 8 #include "fbnic_netdev.h" 9 10 #define DW_VENDOR BIT(15) 11 #define FBNIC_PCS_VENDOR BIT(9) 12 #define FBNIC_PCS_ZERO_MASK (DW_VENDOR - FBNIC_PCS_VENDOR) 13 14 static int 15 fbnic_mdio_read_pmd(struct fbnic_dev *fbd, int addr, int regnum) 16 { 17 u8 aui = FBNIC_AUI_UNKNOWN; 18 struct fbnic_net *fbn; 19 int ret = 0; 20 21 /* We don't need a second PMD, just one can handle both lanes */ 22 if (addr) 23 return 0; 24 25 if (fbd->netdev) { 26 fbn = netdev_priv(fbd->netdev); 27 if (fbn->aui < FBNIC_AUI_UNKNOWN) 28 aui = fbn->aui; 29 } 30 31 switch (regnum) { 32 case MDIO_DEVID1: 33 ret = MP_FBNIC_XPCS_PMA_100G_ID >> 16; 34 break; 35 case MDIO_DEVID2: 36 ret = MP_FBNIC_XPCS_PMA_100G_ID & 0xffff; 37 break; 38 case MDIO_DEVS1: 39 ret = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS; 40 break; 41 case MDIO_STAT2: 42 ret = MDIO_STAT2_DEVPRST_VAL; 43 break; 44 case MDIO_PMA_RXDET: 45 /* If training isn't complete default to 0 */ 46 if (fbd->pmd_state != FBNIC_PMD_SEND_DATA) 47 break; 48 /* Report either 1 or 2 lanes detected depending on config */ 49 ret = (MDIO_PMD_RXDET_GLOBAL | MDIO_PMD_RXDET_0) | 50 ((aui & FBNIC_AUI_MODE_R2) * 51 (MDIO_PMD_RXDET_1 / FBNIC_AUI_MODE_R2)); 52 break; 53 default: 54 break; 55 } 56 57 dev_dbg(fbd->dev, 58 "SWMII PMD Rd: Addr: %d RegNum: %d Value: 0x%04x\n", 59 addr, regnum, ret); 60 61 return ret; 62 } 63 64 static int 65 fbnic_mdio_read_pcs(struct fbnic_dev *fbd, int addr, int regnum) 66 { 67 int ret, offset = 0; 68 69 /* We will need access to both PCS instances to get config info */ 70 if (addr >= 2) 71 return 0; 72 73 /* Report 0 for reserved registers */ 74 if (regnum & FBNIC_PCS_ZERO_MASK) 75 return 0; 76 77 /* Intercept and return correct ID for PCS */ 78 if (regnum == MDIO_DEVID1) 79 return DW_XPCS_ID >> 16; 80 if (regnum == MDIO_DEVID2) 81 return DW_XPCS_ID & 0xffff; 82 if (regnum == MDIO_DEVS1) 83 return MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS; 84 85 /* Swap vendor page bit for FBNIC PCS vendor page bit */ 86 if (regnum & DW_VENDOR) 87 offset ^= DW_VENDOR | FBNIC_PCS_VENDOR; 88 89 ret = fbnic_rd32(fbd, FBNIC_PCS_PAGE(addr) + (regnum ^ offset)); 90 91 dev_dbg(fbd->dev, 92 "SWMII PCS Rd: Addr: %d RegNum: %d Value: 0x%04x\n", 93 addr, regnum, ret); 94 95 return ret; 96 } 97 98 static int 99 fbnic_mdio_read_c45(struct mii_bus *bus, int addr, int devnum, int regnum) 100 { 101 struct fbnic_dev *fbd = bus->priv; 102 103 if (devnum == MDIO_MMD_PMAPMD) 104 return fbnic_mdio_read_pmd(fbd, addr, regnum); 105 106 if (devnum == MDIO_MMD_PCS) 107 return fbnic_mdio_read_pcs(fbd, addr, regnum); 108 109 return 0; 110 } 111 112 static void 113 fbnic_mdio_write_pmd(struct fbnic_dev *fbd, int addr, int regnum, u16 val) 114 { 115 dev_dbg(fbd->dev, 116 "SWMII PMD Wr: Addr: %d RegNum: %d Value: 0x%04x\n", 117 addr, regnum, val); 118 } 119 120 static void 121 fbnic_mdio_write_pcs(struct fbnic_dev *fbd, int addr, int regnum, u16 val) 122 { 123 dev_dbg(fbd->dev, 124 "SWMII PCS Wr: Addr: %d RegNum: %d Value: 0x%04x\n", 125 addr, regnum, val); 126 127 /* Allow access to both halves of PCS for 50R2 config */ 128 if (addr > 2) 129 return; 130 131 /* Skip write for reserved registers */ 132 if (regnum & FBNIC_PCS_ZERO_MASK) 133 return; 134 135 /* Swap vendor page bit for FBNIC PCS vendor page bit */ 136 if (regnum & DW_VENDOR) 137 regnum ^= DW_VENDOR | FBNIC_PCS_VENDOR; 138 139 fbnic_wr32(fbd, FBNIC_PCS_PAGE(addr) + regnum, val); 140 } 141 142 static int 143 fbnic_mdio_write_c45(struct mii_bus *bus, int addr, int devnum, 144 int regnum, u16 val) 145 { 146 struct fbnic_dev *fbd = bus->priv; 147 148 if (devnum == MDIO_MMD_PMAPMD) 149 fbnic_mdio_write_pmd(fbd, addr, regnum, val); 150 151 if (devnum == MDIO_MMD_PCS) 152 fbnic_mdio_write_pcs(fbd, addr, regnum, val); 153 154 return 0; 155 } 156 157 /** 158 * fbnic_mdiobus_create - Create an MDIO bus to allow interfacing w/ PHYs 159 * @fbd: Pointer to FBNIC device structure to populate bus on 160 * 161 * Initialize an MDIO bus and place a pointer to it on the fbd struct. This bus 162 * will be used to interface with the PMA/PMD and PCS. 163 * 164 * Return: 0 on success, negative on failure 165 **/ 166 int fbnic_mdiobus_create(struct fbnic_dev *fbd) 167 { 168 struct mii_bus *bus; 169 int err; 170 171 bus = devm_mdiobus_alloc(fbd->dev); 172 if (!bus) 173 return -ENOMEM; 174 175 bus->name = "fbnic_mii_bus"; 176 bus->read_c45 = &fbnic_mdio_read_c45; 177 bus->write_c45 = &fbnic_mdio_write_c45; 178 179 /* Disable PHY auto probing. We will add PCS manually */ 180 bus->phy_mask = ~0; 181 182 bus->parent = fbd->dev; 183 bus->priv = fbd; 184 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(fbd->dev)); 185 186 err = devm_mdiobus_register(fbd->dev, bus); 187 if (err) { 188 dev_err(fbd->dev, "Failed to create MDIO bus: %d\n", err); 189 return err; 190 } 191 192 fbd->mdio_bus = bus; 193 194 return 0; 195 } 196