Add limited support for the etrax ethernet controller.
[qemu/qemu-JZ.git] / hw / etraxfs_eth.c
blobcf115cb305ad71833e7cb2ce8278d58b90fd71d3
1 /*
2 * QEMU ETRAX Ethernet Controller.
4 * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
25 #include <stdio.h>
26 #include "hw.h"
27 #include "net.h"
29 #include "etraxfs_dma.h"
31 #define D(x)
33 #define R_STAT 0x2c
34 #define RW_MGM_CTRL 0x28
35 #define FS_ETH_MAX_REGS 0x5c
39 struct qemu_phy
41 uint32_t regs[32];
43 unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
44 void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
47 static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
49 int regnum;
50 unsigned r = 0;
52 regnum = req & 0x1f;
54 switch (regnum) {
55 case 1:
56 /* MR1. */
57 /* Speeds and modes. */
58 r |= (1 << 13) | (1 << 14);
59 r |= (1 << 11) | (1 << 12);
60 r |= (1 << 5); /* Autoneg complete. */
61 r |= (1 << 3); /* Autoneg able. */
62 r |= (1 << 2); /* Link. */
63 break;
64 default:
65 r = phy->regs[regnum];
66 break;
68 D(printf("%s %x = reg[%d]\n", __func__, r, regnum));
69 return r;
72 static void
73 tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
75 int regnum;
77 regnum = req & 0x1f;
78 D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
79 switch (regnum) {
80 default:
81 phy->regs[regnum] = data;
82 break;
86 static void
87 tdk_init(struct qemu_phy *phy)
89 phy->read = tdk_read;
90 phy->write = tdk_write;
93 struct qemu_mdio
95 /* bus. */
96 int mdc;
97 int mdio;
99 /* decoder. */
100 enum {
101 PREAMBLE,
102 SOF,
103 OPC,
104 ADDR,
105 REQ,
106 TURNAROUND,
107 DATA
108 } state;
109 unsigned int drive;
111 unsigned int cnt;
112 unsigned int addr;
113 unsigned int opc;
114 unsigned int req;
115 unsigned int data;
117 struct qemu_phy *devs[32];
120 static void
121 mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
123 bus->devs[addr & 0x1f] = phy;
126 static void
127 mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
129 bus->devs[addr & 0x1f] = NULL;
132 static void mdio_read_req(struct qemu_mdio *bus)
134 struct qemu_phy *phy;
136 phy = bus->devs[bus->addr];
137 if (phy && phy->read)
138 bus->data = phy->read(phy, bus->req);
139 else
140 bus->data = 0xffff;
143 static void mdio_write_req(struct qemu_mdio *bus)
145 struct qemu_phy *phy;
147 phy = bus->devs[bus->addr];
148 if (phy && phy->write)
149 phy->write(phy, bus->req, bus->data);
152 static void mdio_cycle(struct qemu_mdio *bus)
154 bus->cnt++;
156 D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
157 bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
158 #if 0
159 if (bus->mdc)
160 printf("%d", bus->mdio);
161 #endif
162 switch (bus->state)
164 case PREAMBLE:
165 if (bus->mdc) {
166 if (bus->cnt >= (32 * 2) && !bus->mdio) {
167 bus->cnt = 0;
168 bus->state = SOF;
169 bus->data = 0;
172 break;
173 case SOF:
174 if (bus->mdc) {
175 if (bus->mdio != 1)
176 printf("WARNING: no SOF\n");
177 if (bus->cnt == 1*2) {
178 bus->cnt = 0;
179 bus->opc = 0;
180 bus->state = OPC;
183 break;
184 case OPC:
185 if (bus->mdc) {
186 bus->opc <<= 1;
187 bus->opc |= bus->mdio & 1;
188 if (bus->cnt == 2*2) {
189 bus->cnt = 0;
190 bus->addr = 0;
191 bus->state = ADDR;
194 break;
195 case ADDR:
196 if (bus->mdc) {
197 bus->addr <<= 1;
198 bus->addr |= bus->mdio & 1;
200 if (bus->cnt == 5*2) {
201 bus->cnt = 0;
202 bus->req = 0;
203 bus->state = REQ;
206 break;
207 case REQ:
208 if (bus->mdc) {
209 bus->req <<= 1;
210 bus->req |= bus->mdio & 1;
211 if (bus->cnt == 5*2) {
212 bus->cnt = 0;
213 bus->state = TURNAROUND;
216 break;
217 case TURNAROUND:
218 if (bus->mdc && bus->cnt == 2*2) {
219 bus->mdio = 0;
220 bus->cnt = 0;
222 if (bus->opc == 2) {
223 bus->drive = 1;
224 mdio_read_req(bus);
225 bus->mdio = bus->data & 1;
227 bus->state = DATA;
229 break;
230 case DATA:
231 if (!bus->mdc) {
232 if (bus->drive) {
233 bus->mdio = bus->data & 1;
234 bus->data >>= 1;
236 } else {
237 if (!bus->drive) {
238 bus->data <<= 1;
239 bus->data |= bus->mdio;
241 if (bus->cnt == 16 * 2) {
242 bus->cnt = 0;
243 bus->state = PREAMBLE;
244 mdio_write_req(bus);
247 break;
248 default:
249 break;
254 struct fs_eth
256 CPUState *env;
257 qemu_irq *irq;
258 target_phys_addr_t base;
259 VLANClientState *vc;
260 uint8_t macaddr[6];
261 int ethregs;
263 uint32_t regs[FS_ETH_MAX_REGS];
265 unsigned char rx_fifo[1536];
266 int rx_fifo_len;
267 int rx_fifo_pos;
269 struct etraxfs_dma_client *dma_out;
270 struct etraxfs_dma_client *dma_in;
272 /* MDIO bus. */
273 struct qemu_mdio mdio_bus;
274 /* PHY. */
275 struct qemu_phy phy;
278 static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr)
280 struct fs_eth *eth = opaque;
281 CPUState *env = eth->env;
282 cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n",
283 addr, env->pc);
284 return 0;
287 static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
289 struct fs_eth *eth = opaque;
290 D(CPUState *env = eth->env);
291 uint32_t r = 0;
293 /* Make addr relative to this instances base. */
294 addr -= eth->base;
295 switch (addr) {
296 case R_STAT:
297 /* Attach an MDIO/PHY abstraction. */
298 r = eth->mdio_bus.mdio & 1;
299 break;
300 default:
301 r = eth->regs[addr];
302 D(printf ("%s %x p=%x\n", __func__, addr, env->pc));
303 break;
305 return r;
308 static void
309 eth_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value)
311 struct fs_eth *eth = opaque;
312 CPUState *env = eth->env;
313 cpu_abort(env, "Unsupported short access. reg=%x pc=%x.\n",
314 addr, env->pc);
317 static void
318 eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
320 struct fs_eth *eth = opaque;
321 CPUState *env = eth->env;
323 /* Make addr relative to this instances base. */
324 addr -= eth->base;
325 switch (addr)
327 case RW_MGM_CTRL:
328 /* Attach an MDIO/PHY abstraction. */
329 if (value & 2)
330 eth->mdio_bus.mdio = value & 1;
331 if (eth->mdio_bus.mdc != (value & 4))
332 mdio_cycle(&eth->mdio_bus);
333 eth->mdio_bus.mdc = !!(value & 4);
334 break;
336 default:
337 printf ("%s %x %x pc=%x\n",
338 __func__, addr, value, env->pc);
339 break;
343 static int eth_can_receive(void *opaque)
345 struct fs_eth *eth = opaque;
346 int r;
348 r = eth->rx_fifo_len == 0;
349 if (!r) {
350 /* TODO: signal fifo overrun. */
351 printf("PACKET LOSS!\n");
353 return r;
356 static void eth_receive(void *opaque, const uint8_t *buf, int size)
358 struct fs_eth *eth = opaque;
359 if (size > sizeof(eth->rx_fifo)) {
360 /* TODO: signal error. */
361 } else {
362 memcpy(eth->rx_fifo, buf, size);
363 /* +4, HW passes the CRC to sw. */
364 eth->rx_fifo_len = size + 4;
365 eth->rx_fifo_pos = 0;
369 static void eth_rx_pull(void *opaque)
371 struct fs_eth *eth = opaque;
372 int len;
373 if (eth->rx_fifo_len) {
374 D(printf("%s %d\n", __func__, eth->rx_fifo_len));
375 #if 0
377 int i;
378 for (i = 0; i < 32; i++)
379 printf("%2.2x", eth->rx_fifo[i]);
380 printf("\n");
382 #endif
383 len = etraxfs_dmac_input(eth->dma_in,
384 eth->rx_fifo + eth->rx_fifo_pos,
385 eth->rx_fifo_len, 1);
386 eth->rx_fifo_len -= len;
387 eth->rx_fifo_pos += len;
391 static int eth_tx_push(void *opaque, unsigned char *buf, int len)
393 struct fs_eth *eth = opaque;
395 D(printf("%s buf=%p len=%d\n", __func__, buf, len));
396 qemu_send_packet(eth->vc, buf, len);
397 return len;
400 static CPUReadMemoryFunc *eth_read[] = {
401 &eth_rinvalid,
402 &eth_rinvalid,
403 &eth_readl,
406 static CPUWriteMemoryFunc *eth_write[] = {
407 &eth_winvalid,
408 &eth_winvalid,
409 &eth_writel,
412 void *etraxfs_eth_init(NICInfo *nd, CPUState *env,
413 qemu_irq *irq, target_phys_addr_t base)
415 struct etraxfs_dma_client *dma = NULL;
416 struct fs_eth *eth = NULL;
418 dma = qemu_mallocz(sizeof *dma * 2);
419 if (!dma)
420 return NULL;
422 eth = qemu_mallocz(sizeof *eth);
423 if (!eth)
424 goto err;
426 dma[0].client.push = eth_tx_push;
427 dma[0].client.opaque = eth;
428 dma[1].client.opaque = eth;
429 dma[1].client.pull = eth_rx_pull;
431 eth->env = env;
432 eth->base = base;
433 eth->irq = irq;
434 eth->dma_out = dma;
435 eth->dma_in = dma + 1;
436 memcpy(eth->macaddr, nd->macaddr, 6);
438 /* Connect the phy. */
439 tdk_init(&eth->phy);
440 mdio_attach(&eth->mdio_bus, &eth->phy, 0x1);
442 eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth);
443 cpu_register_physical_memory (base, 0x5c, eth->ethregs);
445 eth->vc = qemu_new_vlan_client(nd->vlan,
446 eth_receive, eth_can_receive, eth);
448 return dma;
449 err:
450 qemu_free(eth);
451 qemu_free(dma);
452 return NULL;