dv-eth_phy.c revision 1.1.1.4.2.1 1 1.1 christos /* Ethernet Physical Receiver model.
2 1.1 christos
3 1.1.1.4.2.1 pgoyette Copyright (C) 2010-2016 Free Software Foundation, Inc.
4 1.1 christos Contributed by Analog Devices, Inc.
5 1.1 christos
6 1.1 christos This file is part of simulators.
7 1.1 christos
8 1.1 christos This program is free software; you can redistribute it and/or modify
9 1.1 christos it under the terms of the GNU General Public License as published by
10 1.1 christos the Free Software Foundation; either version 3 of the License, or
11 1.1 christos (at your option) any later version.
12 1.1 christos
13 1.1 christos This program is distributed in the hope that it will be useful,
14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 1.1 christos GNU General Public License for more details.
17 1.1 christos
18 1.1 christos You should have received a copy of the GNU General Public License
19 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 1.1 christos
21 1.1 christos #include "config.h"
22 1.1 christos
23 1.1 christos #include "sim-main.h"
24 1.1 christos #include "devices.h"
25 1.1 christos
26 1.1.1.2 christos #if defined (HAVE_LINUX_MII_H) && defined (HAVE_LINUX_TYPES_H)
27 1.1 christos
28 1.1 christos /* Workaround old/broken linux headers. */
29 1.1.1.2 christos #include <linux/types.h>
30 1.1 christos #include <linux/mii.h>
31 1.1 christos
32 1.1 christos #define REG_PHY_SIZE 0x20
33 1.1 christos
34 1.1 christos struct eth_phy
35 1.1 christos {
36 1.1 christos bu32 base;
37 1.1 christos bu16 regs[REG_PHY_SIZE];
38 1.1 christos };
39 1.1 christos #define reg_base() offsetof(struct eth_phy, regs[0])
40 1.1 christos #define reg_offset(reg) (offsetof(struct eth_phy, reg) - reg_base())
41 1.1 christos #define reg_idx(reg) (reg_offset (reg) / 4)
42 1.1 christos
43 1.1 christos static const char * const reg_names[] =
44 1.1 christos {
45 1.1 christos [MII_BMCR ] = "MII_BMCR",
46 1.1 christos [MII_BMSR ] = "MII_BMSR",
47 1.1 christos [MII_PHYSID1 ] = "MII_PHYSID1",
48 1.1 christos [MII_PHYSID2 ] = "MII_PHYSID2",
49 1.1 christos [MII_ADVERTISE ] = "MII_ADVERTISE",
50 1.1 christos [MII_LPA ] = "MII_LPA",
51 1.1 christos [MII_EXPANSION ] = "MII_EXPANSION",
52 1.1 christos #ifdef MII_CTRL1000
53 1.1 christos [MII_CTRL1000 ] = "MII_CTRL1000",
54 1.1 christos #endif
55 1.1 christos #ifdef MII_STAT1000
56 1.1 christos [MII_STAT1000 ] = "MII_STAT1000",
57 1.1 christos #endif
58 1.1 christos #ifdef MII_ESTATUS
59 1.1 christos [MII_ESTATUS ] = "MII_ESTATUS",
60 1.1 christos #endif
61 1.1 christos [MII_DCOUNTER ] = "MII_DCOUNTER",
62 1.1 christos [MII_FCSCOUNTER ] = "MII_FCSCOUNTER",
63 1.1 christos [MII_NWAYTEST ] = "MII_NWAYTEST",
64 1.1 christos [MII_RERRCOUNTER] = "MII_RERRCOUNTER",
65 1.1 christos [MII_SREVISION ] = "MII_SREVISION",
66 1.1 christos [MII_RESV1 ] = "MII_RESV1",
67 1.1 christos [MII_LBRERROR ] = "MII_LBRERROR",
68 1.1 christos [MII_PHYADDR ] = "MII_PHYADDR",
69 1.1 christos [MII_RESV2 ] = "MII_RESV2",
70 1.1 christos [MII_TPISTATUS ] = "MII_TPISTATUS",
71 1.1 christos [MII_NCONFIG ] = "MII_NCONFIG",
72 1.1 christos };
73 1.1 christos #define mmr_name(off) (reg_names[off] ? : "<INV>")
74 1.1 christos #define mmr_off reg_off
75 1.1 christos
76 1.1 christos static unsigned
77 1.1 christos eth_phy_io_write_buffer (struct hw *me, const void *source,
78 1.1 christos int space, address_word addr, unsigned nr_bytes)
79 1.1 christos {
80 1.1 christos struct eth_phy *phy = hw_data (me);
81 1.1 christos bu16 reg_off;
82 1.1 christos bu16 value;
83 1.1 christos bu16 *valuep;
84 1.1 christos
85 1.1 christos value = dv_load_2 (source);
86 1.1 christos
87 1.1 christos reg_off = addr - phy->base;
88 1.1 christos valuep = (void *)((unsigned long)phy + reg_base() + reg_off);
89 1.1 christos
90 1.1 christos HW_TRACE_WRITE ();
91 1.1 christos
92 1.1 christos switch (reg_off)
93 1.1 christos {
94 1.1 christos case MII_BMCR:
95 1.1 christos *valuep = value;
96 1.1 christos break;
97 1.1 christos case MII_PHYSID1:
98 1.1 christos case MII_PHYSID2:
99 1.1 christos /* Discard writes to these. */
100 1.1 christos break;
101 1.1 christos default:
102 1.1 christos /* XXX: Discard writes to unknown regs ? */
103 1.1 christos *valuep = value;
104 1.1 christos break;
105 1.1 christos }
106 1.1 christos
107 1.1 christos return nr_bytes;
108 1.1 christos }
109 1.1 christos
110 1.1 christos static unsigned
111 1.1 christos eth_phy_io_read_buffer (struct hw *me, void *dest,
112 1.1 christos int space, address_word addr, unsigned nr_bytes)
113 1.1 christos {
114 1.1 christos struct eth_phy *phy = hw_data (me);
115 1.1 christos bu16 reg_off;
116 1.1 christos bu16 *valuep;
117 1.1 christos
118 1.1 christos reg_off = addr - phy->base;
119 1.1 christos valuep = (void *)((unsigned long)phy + reg_base() + reg_off);
120 1.1 christos
121 1.1 christos HW_TRACE_READ ();
122 1.1 christos
123 1.1 christos switch (reg_off)
124 1.1 christos {
125 1.1 christos case MII_BMCR:
126 1.1 christos dv_store_2 (dest, *valuep);
127 1.1 christos break;
128 1.1 christos case MII_BMSR:
129 1.1 christos /* XXX: Let people control this ? */
130 1.1 christos *valuep = BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF |
131 1.1 christos BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE | BMSR_LSTATUS;
132 1.1 christos dv_store_2 (dest, *valuep);
133 1.1 christos break;
134 1.1 christos case MII_LPA:
135 1.1 christos /* XXX: Let people control this ? */
136 1.1 christos *valuep = LPA_100FULL | LPA_100HALF | LPA_10FULL | LPA_10HALF;
137 1.1 christos dv_store_2 (dest, *valuep);
138 1.1 christos break;
139 1.1 christos default:
140 1.1 christos dv_store_2 (dest, *valuep);
141 1.1 christos break;
142 1.1 christos }
143 1.1 christos
144 1.1 christos return nr_bytes;
145 1.1 christos }
146 1.1 christos
147 1.1 christos static void
148 1.1 christos attach_eth_phy_regs (struct hw *me, struct eth_phy *phy)
149 1.1 christos {
150 1.1 christos address_word attach_address;
151 1.1 christos int attach_space;
152 1.1 christos unsigned attach_size;
153 1.1 christos reg_property_spec reg;
154 1.1 christos
155 1.1 christos if (hw_find_property (me, "reg") == NULL)
156 1.1 christos hw_abort (me, "Missing \"reg\" property");
157 1.1 christos
158 1.1 christos if (!hw_find_reg_array_property (me, "reg", 0, ®))
159 1.1 christos hw_abort (me, "\"reg\" property must contain three addr/size entries");
160 1.1 christos
161 1.1 christos hw_unit_address_to_attach_address (hw_parent (me),
162 1.1 christos ®.address,
163 1.1 christos &attach_space, &attach_address, me);
164 1.1 christos hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me);
165 1.1 christos
166 1.1 christos if (attach_size != REG_PHY_SIZE)
167 1.1 christos hw_abort (me, "\"reg\" size must be %#x", REG_PHY_SIZE);
168 1.1 christos
169 1.1 christos hw_attach_address (hw_parent (me),
170 1.1 christos 0, attach_space, attach_address, attach_size, me);
171 1.1 christos
172 1.1 christos phy->base = attach_address;
173 1.1 christos }
174 1.1 christos
175 1.1 christos static void
176 1.1 christos eth_phy_finish (struct hw *me)
177 1.1 christos {
178 1.1 christos struct eth_phy *phy;
179 1.1 christos
180 1.1 christos phy = HW_ZALLOC (me, struct eth_phy);
181 1.1 christos
182 1.1 christos set_hw_data (me, phy);
183 1.1 christos set_hw_io_read_buffer (me, eth_phy_io_read_buffer);
184 1.1 christos set_hw_io_write_buffer (me, eth_phy_io_write_buffer);
185 1.1 christos
186 1.1 christos attach_eth_phy_regs (me, phy);
187 1.1 christos
188 1.1 christos /* Initialize the PHY. */
189 1.1 christos phy->regs[MII_PHYSID1] = 0; /* Unassigned Vendor */
190 1.1 christos phy->regs[MII_PHYSID2] = 0xAD; /* Product */
191 1.1 christos }
192 1.1 christos
193 1.1 christos #else
194 1.1 christos
195 1.1 christos static void
196 1.1 christos eth_phy_finish (struct hw *me)
197 1.1 christos {
198 1.1 christos HW_TRACE ((me, "No linux/mii.h support found"));
199 1.1 christos }
200 1.1 christos
201 1.1 christos #endif
202 1.1 christos
203 1.1 christos const struct hw_descriptor dv_eth_phy_descriptor[] =
204 1.1 christos {
205 1.1 christos {"eth_phy", eth_phy_finish,},
206 1.1 christos {NULL, NULL},
207 1.1 christos };
208