dv-eth_phy.c revision 1.1.1.10 1 1.1 christos /* Ethernet Physical Receiver model.
2 1.1 christos
3 1.1.1.10 christos Copyright (C) 2010-2024 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.1.9 christos /* This must come before any other includes. */
22 1.1.1.9 christos #include "defs.h"
23 1.1 christos
24 1.1 christos #include "sim-main.h"
25 1.1 christos #include "devices.h"
26 1.1 christos
27 1.1.1.2 christos #if defined (HAVE_LINUX_MII_H) && defined (HAVE_LINUX_TYPES_H)
28 1.1 christos
29 1.1 christos /* Workaround old/broken linux headers. */
30 1.1.1.2 christos #include <linux/types.h>
31 1.1 christos #include <linux/mii.h>
32 1.1 christos
33 1.1 christos #define REG_PHY_SIZE 0x20
34 1.1 christos
35 1.1 christos struct eth_phy
36 1.1 christos {
37 1.1 christos bu32 base;
38 1.1 christos bu16 regs[REG_PHY_SIZE];
39 1.1 christos };
40 1.1 christos #define reg_base() offsetof(struct eth_phy, regs[0])
41 1.1 christos #define reg_offset(reg) (offsetof(struct eth_phy, reg) - reg_base())
42 1.1 christos #define reg_idx(reg) (reg_offset (reg) / 4)
43 1.1 christos
44 1.1 christos static const char * const reg_names[] =
45 1.1 christos {
46 1.1 christos [MII_BMCR ] = "MII_BMCR",
47 1.1 christos [MII_BMSR ] = "MII_BMSR",
48 1.1 christos [MII_PHYSID1 ] = "MII_PHYSID1",
49 1.1 christos [MII_PHYSID2 ] = "MII_PHYSID2",
50 1.1 christos [MII_ADVERTISE ] = "MII_ADVERTISE",
51 1.1 christos [MII_LPA ] = "MII_LPA",
52 1.1 christos [MII_EXPANSION ] = "MII_EXPANSION",
53 1.1 christos #ifdef MII_CTRL1000
54 1.1 christos [MII_CTRL1000 ] = "MII_CTRL1000",
55 1.1 christos #endif
56 1.1 christos #ifdef MII_STAT1000
57 1.1 christos [MII_STAT1000 ] = "MII_STAT1000",
58 1.1 christos #endif
59 1.1 christos #ifdef MII_ESTATUS
60 1.1 christos [MII_ESTATUS ] = "MII_ESTATUS",
61 1.1 christos #endif
62 1.1 christos [MII_DCOUNTER ] = "MII_DCOUNTER",
63 1.1 christos [MII_FCSCOUNTER ] = "MII_FCSCOUNTER",
64 1.1 christos [MII_NWAYTEST ] = "MII_NWAYTEST",
65 1.1 christos [MII_RERRCOUNTER] = "MII_RERRCOUNTER",
66 1.1 christos [MII_SREVISION ] = "MII_SREVISION",
67 1.1 christos [MII_RESV1 ] = "MII_RESV1",
68 1.1 christos [MII_LBRERROR ] = "MII_LBRERROR",
69 1.1 christos [MII_PHYADDR ] = "MII_PHYADDR",
70 1.1 christos [MII_RESV2 ] = "MII_RESV2",
71 1.1 christos [MII_TPISTATUS ] = "MII_TPISTATUS",
72 1.1 christos [MII_NCONFIG ] = "MII_NCONFIG",
73 1.1 christos };
74 1.1 christos #define mmr_name(off) (reg_names[off] ? : "<INV>")
75 1.1 christos #define mmr_off reg_off
76 1.1 christos
77 1.1 christos static unsigned
78 1.1 christos eth_phy_io_write_buffer (struct hw *me, const void *source,
79 1.1 christos int space, address_word addr, unsigned nr_bytes)
80 1.1 christos {
81 1.1 christos struct eth_phy *phy = hw_data (me);
82 1.1 christos bu16 reg_off;
83 1.1 christos bu16 value;
84 1.1 christos bu16 *valuep;
85 1.1 christos
86 1.1 christos value = dv_load_2 (source);
87 1.1 christos
88 1.1 christos reg_off = addr - phy->base;
89 1.1.1.9 christos valuep = (void *)((uintptr_t)phy + reg_base() + reg_off);
90 1.1 christos
91 1.1 christos HW_TRACE_WRITE ();
92 1.1 christos
93 1.1 christos switch (reg_off)
94 1.1 christos {
95 1.1 christos case MII_BMCR:
96 1.1 christos *valuep = value;
97 1.1 christos break;
98 1.1 christos case MII_PHYSID1:
99 1.1 christos case MII_PHYSID2:
100 1.1 christos /* Discard writes to these. */
101 1.1 christos break;
102 1.1 christos default:
103 1.1 christos /* XXX: Discard writes to unknown regs ? */
104 1.1 christos *valuep = value;
105 1.1 christos break;
106 1.1 christos }
107 1.1 christos
108 1.1 christos return nr_bytes;
109 1.1 christos }
110 1.1 christos
111 1.1 christos static unsigned
112 1.1 christos eth_phy_io_read_buffer (struct hw *me, void *dest,
113 1.1 christos int space, address_word addr, unsigned nr_bytes)
114 1.1 christos {
115 1.1 christos struct eth_phy *phy = hw_data (me);
116 1.1 christos bu16 reg_off;
117 1.1 christos bu16 *valuep;
118 1.1 christos
119 1.1 christos reg_off = addr - phy->base;
120 1.1.1.9 christos valuep = (void *)((uintptr_t)phy + reg_base() + reg_off);
121 1.1 christos
122 1.1 christos HW_TRACE_READ ();
123 1.1 christos
124 1.1 christos switch (reg_off)
125 1.1 christos {
126 1.1 christos case MII_BMCR:
127 1.1 christos dv_store_2 (dest, *valuep);
128 1.1 christos break;
129 1.1 christos case MII_BMSR:
130 1.1 christos /* XXX: Let people control this ? */
131 1.1 christos *valuep = BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF |
132 1.1 christos BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE | BMSR_LSTATUS;
133 1.1 christos dv_store_2 (dest, *valuep);
134 1.1 christos break;
135 1.1 christos case MII_LPA:
136 1.1 christos /* XXX: Let people control this ? */
137 1.1 christos *valuep = LPA_100FULL | LPA_100HALF | LPA_10FULL | LPA_10HALF;
138 1.1 christos dv_store_2 (dest, *valuep);
139 1.1 christos break;
140 1.1 christos default:
141 1.1 christos dv_store_2 (dest, *valuep);
142 1.1 christos break;
143 1.1 christos }
144 1.1 christos
145 1.1 christos return nr_bytes;
146 1.1 christos }
147 1.1 christos
148 1.1 christos static void
149 1.1 christos attach_eth_phy_regs (struct hw *me, struct eth_phy *phy)
150 1.1 christos {
151 1.1 christos address_word attach_address;
152 1.1 christos int attach_space;
153 1.1 christos unsigned attach_size;
154 1.1 christos reg_property_spec reg;
155 1.1 christos
156 1.1 christos if (hw_find_property (me, "reg") == NULL)
157 1.1 christos hw_abort (me, "Missing \"reg\" property");
158 1.1 christos
159 1.1 christos if (!hw_find_reg_array_property (me, "reg", 0, ®))
160 1.1 christos hw_abort (me, "\"reg\" property must contain three addr/size entries");
161 1.1 christos
162 1.1 christos hw_unit_address_to_attach_address (hw_parent (me),
163 1.1 christos ®.address,
164 1.1 christos &attach_space, &attach_address, me);
165 1.1 christos hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me);
166 1.1 christos
167 1.1 christos if (attach_size != REG_PHY_SIZE)
168 1.1 christos hw_abort (me, "\"reg\" size must be %#x", REG_PHY_SIZE);
169 1.1 christos
170 1.1 christos hw_attach_address (hw_parent (me),
171 1.1 christos 0, attach_space, attach_address, attach_size, me);
172 1.1 christos
173 1.1 christos phy->base = attach_address;
174 1.1 christos }
175 1.1 christos
176 1.1 christos static void
177 1.1 christos eth_phy_finish (struct hw *me)
178 1.1 christos {
179 1.1 christos struct eth_phy *phy;
180 1.1 christos
181 1.1 christos phy = HW_ZALLOC (me, struct eth_phy);
182 1.1 christos
183 1.1 christos set_hw_data (me, phy);
184 1.1 christos set_hw_io_read_buffer (me, eth_phy_io_read_buffer);
185 1.1 christos set_hw_io_write_buffer (me, eth_phy_io_write_buffer);
186 1.1 christos
187 1.1 christos attach_eth_phy_regs (me, phy);
188 1.1 christos
189 1.1 christos /* Initialize the PHY. */
190 1.1 christos phy->regs[MII_PHYSID1] = 0; /* Unassigned Vendor */
191 1.1 christos phy->regs[MII_PHYSID2] = 0xAD; /* Product */
192 1.1 christos }
193 1.1 christos
194 1.1 christos #else
195 1.1 christos
196 1.1 christos static void
197 1.1 christos eth_phy_finish (struct hw *me)
198 1.1 christos {
199 1.1 christos HW_TRACE ((me, "No linux/mii.h support found"));
200 1.1 christos }
201 1.1 christos
202 1.1 christos #endif
203 1.1 christos
204 1.1 christos const struct hw_descriptor dv_eth_phy_descriptor[] =
205 1.1 christos {
206 1.1 christos {"eth_phy", eth_phy_finish,},
207 1.1 christos {NULL, NULL},
208 1.1 christos };
209