Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Software PHY emulation
0004  *
0005  * Code taken from fixed_phy.c by Russell King.
0006  *
0007  * Author: Vitaly Bordug <vbordug@ru.mvista.com>
0008  *         Anton Vorontsov <avorontsov@ru.mvista.com>
0009  *
0010  * Copyright (c) 2006-2007 MontaVista Software, Inc.
0011  */
0012 #include <linux/export.h>
0013 #include <linux/mii.h>
0014 #include <linux/phy.h>
0015 #include <linux/phy_fixed.h>
0016 
0017 #include "swphy.h"
0018 
0019 #define MII_REGS_NUM 29
0020 
0021 struct swmii_regs {
0022     u16 bmsr;
0023     u16 lpa;
0024     u16 lpagb;
0025     u16 estat;
0026 };
0027 
0028 enum {
0029     SWMII_SPEED_10 = 0,
0030     SWMII_SPEED_100,
0031     SWMII_SPEED_1000,
0032     SWMII_DUPLEX_HALF = 0,
0033     SWMII_DUPLEX_FULL,
0034 };
0035 
0036 /*
0037  * These two tables get bitwise-anded together to produce the final result.
0038  * This means the speed table must contain both duplex settings, and the
0039  * duplex table must contain all speed settings.
0040  */
0041 static const struct swmii_regs speed[] = {
0042     [SWMII_SPEED_10] = {
0043         .lpa   = LPA_10FULL | LPA_10HALF,
0044     },
0045     [SWMII_SPEED_100] = {
0046         .bmsr  = BMSR_100FULL | BMSR_100HALF,
0047         .lpa   = LPA_100FULL | LPA_100HALF,
0048     },
0049     [SWMII_SPEED_1000] = {
0050         .bmsr  = BMSR_ESTATEN,
0051         .lpagb = LPA_1000FULL | LPA_1000HALF,
0052         .estat = ESTATUS_1000_TFULL | ESTATUS_1000_THALF,
0053     },
0054 };
0055 
0056 static const struct swmii_regs duplex[] = {
0057     [SWMII_DUPLEX_HALF] = {
0058         .bmsr  = BMSR_ESTATEN | BMSR_100HALF,
0059         .lpa   = LPA_10HALF | LPA_100HALF,
0060         .lpagb = LPA_1000HALF,
0061         .estat = ESTATUS_1000_THALF,
0062     },
0063     [SWMII_DUPLEX_FULL] = {
0064         .bmsr  = BMSR_ESTATEN | BMSR_100FULL,
0065         .lpa   = LPA_10FULL | LPA_100FULL,
0066         .lpagb = LPA_1000FULL,
0067         .estat = ESTATUS_1000_TFULL,
0068     },
0069 };
0070 
0071 static int swphy_decode_speed(int speed)
0072 {
0073     switch (speed) {
0074     case 1000:
0075         return SWMII_SPEED_1000;
0076     case 100:
0077         return SWMII_SPEED_100;
0078     case 10:
0079         return SWMII_SPEED_10;
0080     default:
0081         return -EINVAL;
0082     }
0083 }
0084 
0085 /**
0086  * swphy_validate_state - validate the software phy status
0087  * @state: software phy status
0088  *
0089  * This checks that we can represent the state stored in @state can be
0090  * represented in the emulated MII registers.  Returns 0 if it can,
0091  * otherwise returns -EINVAL.
0092  */
0093 int swphy_validate_state(const struct fixed_phy_status *state)
0094 {
0095     int err;
0096 
0097     if (state->link) {
0098         err = swphy_decode_speed(state->speed);
0099         if (err < 0) {
0100             pr_warn("swphy: unknown speed\n");
0101             return -EINVAL;
0102         }
0103     }
0104     return 0;
0105 }
0106 EXPORT_SYMBOL_GPL(swphy_validate_state);
0107 
0108 /**
0109  * swphy_read_reg - return a MII register from the fixed phy state
0110  * @reg: MII register
0111  * @state: fixed phy status
0112  *
0113  * Return the MII @reg register generated from the fixed phy state @state.
0114  */
0115 int swphy_read_reg(int reg, const struct fixed_phy_status *state)
0116 {
0117     int speed_index, duplex_index;
0118     u16 bmsr = BMSR_ANEGCAPABLE;
0119     u16 estat = 0;
0120     u16 lpagb = 0;
0121     u16 lpa = 0;
0122 
0123     if (reg > MII_REGS_NUM)
0124         return -1;
0125 
0126     speed_index = swphy_decode_speed(state->speed);
0127     if (WARN_ON(speed_index < 0))
0128         return 0;
0129 
0130     duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF;
0131 
0132     bmsr |= speed[speed_index].bmsr & duplex[duplex_index].bmsr;
0133     estat |= speed[speed_index].estat & duplex[duplex_index].estat;
0134 
0135     if (state->link) {
0136         bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
0137 
0138         lpa   |= speed[speed_index].lpa   & duplex[duplex_index].lpa;
0139         lpagb |= speed[speed_index].lpagb & duplex[duplex_index].lpagb;
0140 
0141         if (state->pause)
0142             lpa |= LPA_PAUSE_CAP;
0143 
0144         if (state->asym_pause)
0145             lpa |= LPA_PAUSE_ASYM;
0146     }
0147 
0148     switch (reg) {
0149     case MII_BMCR:
0150         return BMCR_ANENABLE;
0151     case MII_BMSR:
0152         return bmsr;
0153     case MII_PHYSID1:
0154     case MII_PHYSID2:
0155         return 0;
0156     case MII_LPA:
0157         return lpa;
0158     case MII_STAT1000:
0159         return lpagb;
0160     case MII_ESTATUS:
0161         return estat;
0162 
0163     /*
0164      * We do not support emulating Clause 45 over Clause 22 register
0165      * reads.  Return an error instead of bogus data.
0166      */
0167     case MII_MMD_CTRL:
0168     case MII_MMD_DATA:
0169         return -1;
0170 
0171     default:
0172         return 0xffff;
0173     }
0174 }
0175 EXPORT_SYMBOL_GPL(swphy_read_reg);