123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*
- * Software PHY emulation
- *
- * Code taken from fixed_phy.c by Russell King <rmk+kernel@arm.linux.org.uk>
- *
- * Author: Vitaly Bordug <vbordug@ru.mvista.com>
- * Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * Copyright (c) 2006-2007 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
- #include <linux/export.h>
- #include <linux/mii.h>
- #include <linux/phy.h>
- #include <linux/phy_fixed.h>
- #include "swphy.h"
- #define MII_REGS_NUM 29
- struct swmii_regs {
- u16 bmcr;
- u16 bmsr;
- u16 lpa;
- u16 lpagb;
- };
- enum {
- SWMII_SPEED_10 = 0,
- SWMII_SPEED_100,
- SWMII_SPEED_1000,
- SWMII_DUPLEX_HALF = 0,
- SWMII_DUPLEX_FULL,
- };
- /*
- * These two tables get bitwise-anded together to produce the final result.
- * This means the speed table must contain both duplex settings, and the
- * duplex table must contain all speed settings.
- */
- static const struct swmii_regs speed[] = {
- [SWMII_SPEED_10] = {
- .bmcr = BMCR_FULLDPLX,
- .lpa = LPA_10FULL | LPA_10HALF,
- },
- [SWMII_SPEED_100] = {
- .bmcr = BMCR_FULLDPLX | BMCR_SPEED100,
- .bmsr = BMSR_100FULL | BMSR_100HALF,
- .lpa = LPA_100FULL | LPA_100HALF,
- },
- [SWMII_SPEED_1000] = {
- .bmcr = BMCR_FULLDPLX | BMCR_SPEED1000,
- .bmsr = BMSR_ESTATEN,
- .lpagb = LPA_1000FULL | LPA_1000HALF,
- },
- };
- static const struct swmii_regs duplex[] = {
- [SWMII_DUPLEX_HALF] = {
- .bmcr = ~BMCR_FULLDPLX,
- .bmsr = BMSR_ESTATEN | BMSR_100HALF,
- .lpa = LPA_10HALF | LPA_100HALF,
- .lpagb = LPA_1000HALF,
- },
- [SWMII_DUPLEX_FULL] = {
- .bmcr = ~0,
- .bmsr = BMSR_ESTATEN | BMSR_100FULL,
- .lpa = LPA_10FULL | LPA_100FULL,
- .lpagb = LPA_1000FULL,
- },
- };
- static int swphy_decode_speed(int speed)
- {
- switch (speed) {
- case 1000:
- return SWMII_SPEED_1000;
- case 100:
- return SWMII_SPEED_100;
- case 10:
- return SWMII_SPEED_10;
- default:
- return -EINVAL;
- }
- }
- /**
- * swphy_validate_state - validate the software phy status
- * @state: software phy status
- *
- * This checks that we can represent the state stored in @state can be
- * represented in the emulated MII registers. Returns 0 if it can,
- * otherwise returns -EINVAL.
- */
- int swphy_validate_state(const struct fixed_phy_status *state)
- {
- int err;
- if (state->link) {
- err = swphy_decode_speed(state->speed);
- if (err < 0) {
- pr_warn("swphy: unknown speed\n");
- return -EINVAL;
- }
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(swphy_validate_state);
- /**
- * swphy_read_reg - return a MII register from the fixed phy state
- * @reg: MII register
- * @state: fixed phy status
- *
- * Return the MII @reg register generated from the fixed phy state @state.
- */
- int swphy_read_reg(int reg, const struct fixed_phy_status *state)
- {
- int speed_index, duplex_index;
- u16 bmsr = BMSR_ANEGCAPABLE;
- u16 bmcr = 0;
- u16 lpagb = 0;
- u16 lpa = 0;
- if (reg > MII_REGS_NUM)
- return -1;
- speed_index = swphy_decode_speed(state->speed);
- if (WARN_ON(speed_index < 0))
- return 0;
- duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF;
- bmsr |= speed[speed_index].bmsr & duplex[duplex_index].bmsr;
- if (state->link) {
- bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
- bmcr |= speed[speed_index].bmcr & duplex[duplex_index].bmcr;
- lpa |= speed[speed_index].lpa & duplex[duplex_index].lpa;
- lpagb |= speed[speed_index].lpagb & duplex[duplex_index].lpagb;
- if (state->pause)
- lpa |= LPA_PAUSE_CAP;
- if (state->asym_pause)
- lpa |= LPA_PAUSE_ASYM;
- }
- switch (reg) {
- case MII_BMCR:
- return bmcr;
- case MII_BMSR:
- return bmsr;
- case MII_PHYSID1:
- case MII_PHYSID2:
- return 0;
- case MII_LPA:
- return lpa;
- case MII_STAT1000:
- return lpagb;
- /*
- * We do not support emulating Clause 45 over Clause 22 register
- * reads. Return an error instead of bogus data.
- */
- case MII_MMD_CTRL:
- case MII_MMD_DATA:
- return -1;
- default:
- return 0xffff;
- }
- }
- EXPORT_SYMBOL_GPL(swphy_read_reg);
|