1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+
25ae68b0cSRussell King /*
35ae68b0cSRussell King * Software PHY emulation
45ae68b0cSRussell King *
5*4f39467eSRussell King * Code taken from fixed_phy.c by Russell King.
65ae68b0cSRussell King *
75ae68b0cSRussell King * Author: Vitaly Bordug <vbordug@ru.mvista.com>
85ae68b0cSRussell King * Anton Vorontsov <avorontsov@ru.mvista.com>
95ae68b0cSRussell King *
105ae68b0cSRussell King * Copyright (c) 2006-2007 MontaVista Software, Inc.
115ae68b0cSRussell King */
125ae68b0cSRussell King #include <linux/export.h>
135ae68b0cSRussell King #include <linux/mii.h>
145ae68b0cSRussell King #include <linux/phy.h>
155ae68b0cSRussell King #include <linux/phy_fixed.h>
165ae68b0cSRussell King
175ae68b0cSRussell King #include "swphy.h"
185ae68b0cSRussell King
1937688e3fSRussell King #define MII_REGS_NUM 29
2037688e3fSRussell King
210629bf17SRussell King struct swmii_regs {
220629bf17SRussell King u16 bmsr;
230629bf17SRussell King u16 lpa;
240629bf17SRussell King u16 lpagb;
252441ba48SHeiner Kallweit u16 estat;
260629bf17SRussell King };
270629bf17SRussell King
280629bf17SRussell King enum {
290629bf17SRussell King SWMII_SPEED_10 = 0,
300629bf17SRussell King SWMII_SPEED_100,
310629bf17SRussell King SWMII_SPEED_1000,
320629bf17SRussell King SWMII_DUPLEX_HALF = 0,
330629bf17SRussell King SWMII_DUPLEX_FULL,
340629bf17SRussell King };
350629bf17SRussell King
360629bf17SRussell King /*
370629bf17SRussell King * These two tables get bitwise-anded together to produce the final result.
380629bf17SRussell King * This means the speed table must contain both duplex settings, and the
390629bf17SRussell King * duplex table must contain all speed settings.
400629bf17SRussell King */
410629bf17SRussell King static const struct swmii_regs speed[] = {
420629bf17SRussell King [SWMII_SPEED_10] = {
430629bf17SRussell King .lpa = LPA_10FULL | LPA_10HALF,
440629bf17SRussell King },
450629bf17SRussell King [SWMII_SPEED_100] = {
460629bf17SRussell King .bmsr = BMSR_100FULL | BMSR_100HALF,
470629bf17SRussell King .lpa = LPA_100FULL | LPA_100HALF,
480629bf17SRussell King },
490629bf17SRussell King [SWMII_SPEED_1000] = {
500629bf17SRussell King .bmsr = BMSR_ESTATEN,
510629bf17SRussell King .lpagb = LPA_1000FULL | LPA_1000HALF,
522441ba48SHeiner Kallweit .estat = ESTATUS_1000_TFULL | ESTATUS_1000_THALF,
530629bf17SRussell King },
540629bf17SRussell King };
550629bf17SRussell King
560629bf17SRussell King static const struct swmii_regs duplex[] = {
570629bf17SRussell King [SWMII_DUPLEX_HALF] = {
580629bf17SRussell King .bmsr = BMSR_ESTATEN | BMSR_100HALF,
590629bf17SRussell King .lpa = LPA_10HALF | LPA_100HALF,
600629bf17SRussell King .lpagb = LPA_1000HALF,
612441ba48SHeiner Kallweit .estat = ESTATUS_1000_THALF,
620629bf17SRussell King },
630629bf17SRussell King [SWMII_DUPLEX_FULL] = {
640629bf17SRussell King .bmsr = BMSR_ESTATEN | BMSR_100FULL,
650629bf17SRussell King .lpa = LPA_10FULL | LPA_100FULL,
660629bf17SRussell King .lpagb = LPA_1000FULL,
672441ba48SHeiner Kallweit .estat = ESTATUS_1000_TFULL,
680629bf17SRussell King },
690629bf17SRussell King };
700629bf17SRussell King
swphy_decode_speed(int speed)710629bf17SRussell King static int swphy_decode_speed(int speed)
720629bf17SRussell King {
730629bf17SRussell King switch (speed) {
740629bf17SRussell King case 1000:
750629bf17SRussell King return SWMII_SPEED_1000;
760629bf17SRussell King case 100:
770629bf17SRussell King return SWMII_SPEED_100;
780629bf17SRussell King case 10:
790629bf17SRussell King return SWMII_SPEED_10;
800629bf17SRussell King default:
810629bf17SRussell King return -EINVAL;
820629bf17SRussell King }
830629bf17SRussell King }
840629bf17SRussell King
855ae68b0cSRussell King /**
8668888ce0SRussell King * swphy_validate_state - validate the software phy status
8768888ce0SRussell King * @state: software phy status
8868888ce0SRussell King *
8968888ce0SRussell King * This checks that we can represent the state stored in @state can be
9068888ce0SRussell King * represented in the emulated MII registers. Returns 0 if it can,
9168888ce0SRussell King * otherwise returns -EINVAL.
9268888ce0SRussell King */
swphy_validate_state(const struct fixed_phy_status * state)9368888ce0SRussell King int swphy_validate_state(const struct fixed_phy_status *state)
9468888ce0SRussell King {
9568888ce0SRussell King int err;
9668888ce0SRussell King
9768888ce0SRussell King if (state->link) {
9868888ce0SRussell King err = swphy_decode_speed(state->speed);
9968888ce0SRussell King if (err < 0) {
10068888ce0SRussell King pr_warn("swphy: unknown speed\n");
10168888ce0SRussell King return -EINVAL;
10268888ce0SRussell King }
10368888ce0SRussell King }
10468888ce0SRussell King return 0;
10568888ce0SRussell King }
10668888ce0SRussell King EXPORT_SYMBOL_GPL(swphy_validate_state);
10768888ce0SRussell King
10868888ce0SRussell King /**
10937688e3fSRussell King * swphy_read_reg - return a MII register from the fixed phy state
11037688e3fSRussell King * @reg: MII register
1115ae68b0cSRussell King * @state: fixed phy status
1125ae68b0cSRussell King *
11337688e3fSRussell King * Return the MII @reg register generated from the fixed phy state @state.
1145ae68b0cSRussell King */
swphy_read_reg(int reg,const struct fixed_phy_status * state)11537688e3fSRussell King int swphy_read_reg(int reg, const struct fixed_phy_status *state)
1165ae68b0cSRussell King {
1170629bf17SRussell King int speed_index, duplex_index;
1185ae68b0cSRussell King u16 bmsr = BMSR_ANEGCAPABLE;
1192441ba48SHeiner Kallweit u16 estat = 0;
1205ae68b0cSRussell King u16 lpagb = 0;
1215ae68b0cSRussell King u16 lpa = 0;
1225ae68b0cSRussell King
12337688e3fSRussell King if (reg > MII_REGS_NUM)
12437688e3fSRussell King return -1;
12537688e3fSRussell King
1260629bf17SRussell King speed_index = swphy_decode_speed(state->speed);
12768888ce0SRussell King if (WARN_ON(speed_index < 0))
12837688e3fSRussell King return 0;
1290629bf17SRussell King
1300629bf17SRussell King duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF;
1310629bf17SRussell King
1320629bf17SRussell King bmsr |= speed[speed_index].bmsr & duplex[duplex_index].bmsr;
1332441ba48SHeiner Kallweit estat |= speed[speed_index].estat & duplex[duplex_index].estat;
1345ae68b0cSRussell King
1355ae68b0cSRussell King if (state->link) {
1365ae68b0cSRussell King bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
1375ae68b0cSRussell King
1380629bf17SRussell King lpa |= speed[speed_index].lpa & duplex[duplex_index].lpa;
1390629bf17SRussell King lpagb |= speed[speed_index].lpagb & duplex[duplex_index].lpagb;
1405ae68b0cSRussell King
1415ae68b0cSRussell King if (state->pause)
1425ae68b0cSRussell King lpa |= LPA_PAUSE_CAP;
1435ae68b0cSRussell King
1445ae68b0cSRussell King if (state->asym_pause)
1455ae68b0cSRussell King lpa |= LPA_PAUSE_ASYM;
1465ae68b0cSRussell King }
1475ae68b0cSRussell King
14837688e3fSRussell King switch (reg) {
14937688e3fSRussell King case MII_BMCR:
150726097d6SHeiner Kallweit return BMCR_ANENABLE;
15137688e3fSRussell King case MII_BMSR:
15237688e3fSRussell King return bmsr;
15337688e3fSRussell King case MII_PHYSID1:
15437688e3fSRussell King case MII_PHYSID2:
15537688e3fSRussell King return 0;
15637688e3fSRussell King case MII_LPA:
15737688e3fSRussell King return lpa;
15837688e3fSRussell King case MII_STAT1000:
15937688e3fSRussell King return lpagb;
1602441ba48SHeiner Kallweit case MII_ESTATUS:
1612441ba48SHeiner Kallweit return estat;
1625ae68b0cSRussell King
16337688e3fSRussell King /*
16437688e3fSRussell King * We do not support emulating Clause 45 over Clause 22 register
16537688e3fSRussell King * reads. Return an error instead of bogus data.
16637688e3fSRussell King */
16737688e3fSRussell King case MII_MMD_CTRL:
16837688e3fSRussell King case MII_MMD_DATA:
16937688e3fSRussell King return -1;
17037688e3fSRussell King
17137688e3fSRussell King default:
17237688e3fSRussell King return 0xffff;
1735ae68b0cSRussell King }
17437688e3fSRussell King }
17537688e3fSRussell King EXPORT_SYMBOL_GPL(swphy_read_reg);
176