phy: separate swphy state validation from register generation
[deliverable/linux.git] / drivers / net / phy / swphy.c
CommitLineData
5ae68b0c
RK
1/*
2 * Software PHY emulation
3 *
4 * Code taken from fixed_phy.c by Russell King <rmk+kernel@arm.linux.org.uk>
5 *
6 * Author: Vitaly Bordug <vbordug@ru.mvista.com>
7 * Anton Vorontsov <avorontsov@ru.mvista.com>
8 *
9 * Copyright (c) 2006-2007 MontaVista Software, Inc.
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 */
16#include <linux/export.h>
17#include <linux/mii.h>
18#include <linux/phy.h>
19#include <linux/phy_fixed.h>
20
21#include "swphy.h"
22
0629bf17
RK
23struct swmii_regs {
24 u16 bmcr;
25 u16 bmsr;
26 u16 lpa;
27 u16 lpagb;
28};
29
30enum {
31 SWMII_SPEED_10 = 0,
32 SWMII_SPEED_100,
33 SWMII_SPEED_1000,
34 SWMII_DUPLEX_HALF = 0,
35 SWMII_DUPLEX_FULL,
36};
37
38/*
39 * These two tables get bitwise-anded together to produce the final result.
40 * This means the speed table must contain both duplex settings, and the
41 * duplex table must contain all speed settings.
42 */
43static const struct swmii_regs speed[] = {
44 [SWMII_SPEED_10] = {
45 .bmcr = BMCR_FULLDPLX,
46 .lpa = LPA_10FULL | LPA_10HALF,
47 },
48 [SWMII_SPEED_100] = {
49 .bmcr = BMCR_FULLDPLX | BMCR_SPEED100,
50 .bmsr = BMSR_100FULL | BMSR_100HALF,
51 .lpa = LPA_100FULL | LPA_100HALF,
52 },
53 [SWMII_SPEED_1000] = {
54 .bmcr = BMCR_FULLDPLX | BMCR_SPEED1000,
55 .bmsr = BMSR_ESTATEN,
56 .lpagb = LPA_1000FULL | LPA_1000HALF,
57 },
58};
59
60static const struct swmii_regs duplex[] = {
61 [SWMII_DUPLEX_HALF] = {
62 .bmcr = ~BMCR_FULLDPLX,
63 .bmsr = BMSR_ESTATEN | BMSR_100HALF,
64 .lpa = LPA_10HALF | LPA_100HALF,
65 .lpagb = LPA_1000HALF,
66 },
67 [SWMII_DUPLEX_FULL] = {
68 .bmcr = ~0,
69 .bmsr = BMSR_ESTATEN | BMSR_100FULL,
70 .lpa = LPA_10FULL | LPA_100FULL,
71 .lpagb = LPA_1000FULL,
72 },
73};
74
75static int swphy_decode_speed(int speed)
76{
77 switch (speed) {
78 case 1000:
79 return SWMII_SPEED_1000;
80 case 100:
81 return SWMII_SPEED_100;
82 case 10:
83 return SWMII_SPEED_10;
84 default:
85 return -EINVAL;
86 }
87}
88
68888ce0
RK
89/**
90 * swphy_validate_state - validate the software phy status
91 * @state: software phy status
92 *
93 * This checks that we can represent the state stored in @state can be
94 * represented in the emulated MII registers. Returns 0 if it can,
95 * otherwise returns -EINVAL.
96 */
97int swphy_validate_state(const struct fixed_phy_status *state)
98{
99 int err;
100
101 if (state->link) {
102 err = swphy_decode_speed(state->speed);
103 if (err < 0) {
104 pr_warn("swphy: unknown speed\n");
105 return -EINVAL;
106 }
107 }
108 return 0;
109}
110EXPORT_SYMBOL_GPL(swphy_validate_state);
111
5ae68b0c
RK
112/**
113 * swphy_update_regs - update MII register array with fixed phy state
114 * @regs: array of 32 registers to update
115 * @state: fixed phy status
116 *
117 * Update the array of MII registers with the fixed phy link, speed,
118 * duplex and pause mode settings.
119 */
68888ce0 120void swphy_update_regs(u16 *regs, const struct fixed_phy_status *state)
5ae68b0c 121{
0629bf17 122 int speed_index, duplex_index;
5ae68b0c
RK
123 u16 bmsr = BMSR_ANEGCAPABLE;
124 u16 bmcr = 0;
125 u16 lpagb = 0;
126 u16 lpa = 0;
127
0629bf17 128 speed_index = swphy_decode_speed(state->speed);
68888ce0
RK
129 if (WARN_ON(speed_index < 0))
130 return;
5ae68b0c 131
0629bf17
RK
132 duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF;
133
134 bmsr |= speed[speed_index].bmsr & duplex[duplex_index].bmsr;
135
5ae68b0c
RK
136 if (state->link) {
137 bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
138
0629bf17
RK
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;
5ae68b0c
RK
142
143 if (state->pause)
144 lpa |= LPA_PAUSE_CAP;
145
146 if (state->asym_pause)
147 lpa |= LPA_PAUSE_ASYM;
148 }
149
150 regs[MII_PHYSID1] = 0;
151 regs[MII_PHYSID2] = 0;
152
153 regs[MII_BMSR] = bmsr;
154 regs[MII_BMCR] = bmcr;
155 regs[MII_LPA] = lpa;
156 regs[MII_STAT1000] = lpagb;
5ae68b0c
RK
157}
158EXPORT_SYMBOL_GPL(swphy_update_regs);
This page took 0.033369 seconds and 5 git commands to generate.