1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Software PHY emulation 4 * 5 * Code taken from fixed_phy.c by Russell King <rmk+kernel@arm.linux.org.uk> 6 * 7 * Author: Vitaly Bordug <vbordug@ru.mvista.com> 8 * Anton Vorontsov <avorontsov@ru.mvista.com> 9 * 10 * Copyright (c) 2006-2007 MontaVista Software, Inc. 11 */ 12 #include <linux/export.h> 13 #include <linux/mii.h> 14 #include <linux/phy.h> 15 #include <linux/phy_fixed.h> 16 17 #include "swphy.h" 18 19 #define MII_REGS_NUM 29 20 21 struct swmii_regs { 22 u16 bmcr; 23 u16 bmsr; 24 u16 lpa; 25 u16 lpagb; 26 }; 27 28 enum { 29 SWMII_SPEED_10 = 0, 30 SWMII_SPEED_100, 31 SWMII_SPEED_1000, 32 SWMII_DUPLEX_HALF = 0, 33 SWMII_DUPLEX_FULL, 34 }; 35 36 /* 37 * These two tables get bitwise-anded together to produce the final result. 38 * This means the speed table must contain both duplex settings, and the 39 * duplex table must contain all speed settings. 40 */ 41 static const struct swmii_regs speed[] = { 42 [SWMII_SPEED_10] = { 43 .bmcr = BMCR_FULLDPLX, 44 .lpa = LPA_10FULL | LPA_10HALF, 45 }, 46 [SWMII_SPEED_100] = { 47 .bmcr = BMCR_FULLDPLX | BMCR_SPEED100, 48 .bmsr = BMSR_100FULL | BMSR_100HALF, 49 .lpa = LPA_100FULL | LPA_100HALF, 50 }, 51 [SWMII_SPEED_1000] = { 52 .bmcr = BMCR_FULLDPLX | BMCR_SPEED1000, 53 .bmsr = BMSR_ESTATEN, 54 .lpagb = LPA_1000FULL | LPA_1000HALF, 55 }, 56 }; 57 58 static const struct swmii_regs duplex[] = { 59 [SWMII_DUPLEX_HALF] = { 60 .bmcr = ~BMCR_FULLDPLX, 61 .bmsr = BMSR_ESTATEN | BMSR_100HALF, 62 .lpa = LPA_10HALF | LPA_100HALF, 63 .lpagb = LPA_1000HALF, 64 }, 65 [SWMII_DUPLEX_FULL] = { 66 .bmcr = ~0, 67 .bmsr = BMSR_ESTATEN | BMSR_100FULL, 68 .lpa = LPA_10FULL | LPA_100FULL, 69 .lpagb = LPA_1000FULL, 70 }, 71 }; 72 73 static int swphy_decode_speed(int speed) 74 { 75 switch (speed) { 76 case 1000: 77 return SWMII_SPEED_1000; 78 case 100: 79 return SWMII_SPEED_100; 80 case 10: 81 return SWMII_SPEED_10; 82 default: 83 return -EINVAL; 84 } 85 } 86 87 /** 88 * swphy_validate_state - validate the software phy status 89 * @state: software phy status 90 * 91 * This checks that we can represent the state stored in @state can be 92 * represented in the emulated MII registers. Returns 0 if it can, 93 * otherwise returns -EINVAL. 94 */ 95 int swphy_validate_state(const struct fixed_phy_status *state) 96 { 97 int err; 98 99 if (state->link) { 100 err = swphy_decode_speed(state->speed); 101 if (err < 0) { 102 pr_warn("swphy: unknown speed\n"); 103 return -EINVAL; 104 } 105 } 106 return 0; 107 } 108 EXPORT_SYMBOL_GPL(swphy_validate_state); 109 110 /** 111 * swphy_read_reg - return a MII register from the fixed phy state 112 * @reg: MII register 113 * @state: fixed phy status 114 * 115 * Return the MII @reg register generated from the fixed phy state @state. 116 */ 117 int swphy_read_reg(int reg, const struct fixed_phy_status *state) 118 { 119 int speed_index, duplex_index; 120 u16 bmsr = BMSR_ANEGCAPABLE; 121 u16 bmcr = 0; 122 u16 lpagb = 0; 123 u16 lpa = 0; 124 125 if (reg > MII_REGS_NUM) 126 return -1; 127 128 speed_index = swphy_decode_speed(state->speed); 129 if (WARN_ON(speed_index < 0)) 130 return 0; 131 132 duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF; 133 134 bmsr |= speed[speed_index].bmsr & duplex[duplex_index].bmsr; 135 136 if (state->link) { 137 bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; 138 139 bmcr |= speed[speed_index].bmcr & duplex[duplex_index].bmcr; 140 lpa |= speed[speed_index].lpa & duplex[duplex_index].lpa; 141 lpagb |= speed[speed_index].lpagb & duplex[duplex_index].lpagb; 142 143 if (state->pause) 144 lpa |= LPA_PAUSE_CAP; 145 146 if (state->asym_pause) 147 lpa |= LPA_PAUSE_ASYM; 148 } 149 150 switch (reg) { 151 case MII_BMCR: 152 return bmcr; 153 case MII_BMSR: 154 return bmsr; 155 case MII_PHYSID1: 156 case MII_PHYSID2: 157 return 0; 158 case MII_LPA: 159 return lpa; 160 case MII_STAT1000: 161 return lpagb; 162 163 /* 164 * We do not support emulating Clause 45 over Clause 22 register 165 * reads. Return an error instead of bogus data. 166 */ 167 case MII_MMD_CTRL: 168 case MII_MMD_DATA: 169 return -1; 170 171 default: 172 return 0xffff; 173 } 174 } 175 EXPORT_SYMBOL_GPL(swphy_read_reg); 176