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
29 #include "etraxfs_dma.h"
34 #define RW_MGM_CTRL 0x28
35 #define FS_ETH_MAX_REGS 0x5c
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)
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. */
65 r = phy->regs[regnum];
68 D(printf("%s %x = reg[%d]\n", __func__, r, regnum));
73 tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
78 D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
81 phy->regs[regnum] = data;
87 tdk_init(struct qemu_phy *phy)
90 phy->write = tdk_write;
117 struct qemu_phy *devs[32];
121 mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
123 bus->devs[addr & 0x1f] = phy;
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);
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)
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));
160 printf("%d", bus->mdio);
166 if (bus->cnt >= (32 * 2) && !bus->mdio) {
176 printf("WARNING: no SOF\n");
177 if (bus->cnt == 1*2) {
187 bus->opc |= bus->mdio & 1;
188 if (bus->cnt == 2*2) {
198 bus->addr |= bus->mdio & 1;
200 if (bus->cnt == 5*2) {
210 bus->req |= bus->mdio & 1;
211 if (bus->cnt == 5*2) {
213 bus->state = TURNAROUND;
218 if (bus->mdc && bus->cnt == 2*2) {
225 bus->mdio = bus->data & 1;
233 bus->mdio = bus->data & 1;
239 bus->data |= bus->mdio;
241 if (bus->cnt == 16 * 2) {
243 bus->state = PREAMBLE;
258 target_phys_addr_t base;
263 uint32_t regs[FS_ETH_MAX_REGS];
265 unsigned char rx_fifo[1536];
269 struct etraxfs_dma_client *dma_out;
270 struct etraxfs_dma_client *dma_in;
273 struct qemu_mdio mdio_bus;
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",
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);
293 /* Make addr relative to this instances base. */
297 /* Attach an MDIO/PHY abstraction. */
298 r = eth->mdio_bus.mdio & 1;
302 D(printf ("%s %x p=%x\n", __func__, addr, env->pc));
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",
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. */
328 /* Attach an MDIO/PHY abstraction. */
330 eth->mdio_bus.mdio = value & 1;
331 if (eth->mdio_bus.mdc != (value & 4))
332 mdio_cycle(ð->mdio_bus);
333 eth->mdio_bus.mdc = !!(value & 4);
337 printf ("%s %x %x pc=%x\n",
338 __func__, addr, value, env->pc);
343 static int eth_can_receive(void *opaque)
345 struct fs_eth *eth = opaque;
348 r = eth->rx_fifo_len == 0;
350 /* TODO: signal fifo overrun. */
351 printf("PACKET LOSS!\n");
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. */
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;
373 if (eth->rx_fifo_len) {
374 D(printf("%s %d\n", __func__, eth->rx_fifo_len));
378 for (i = 0; i < 32; i++)
379 printf("%2.2x", eth->rx_fifo[i]);
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);
400 static CPUReadMemoryFunc *eth_read[] = {
406 static CPUWriteMemoryFunc *eth_write[] = {
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);
422 eth = qemu_mallocz(sizeof *eth);
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;
435 eth->dma_in = dma + 1;
436 memcpy(eth->macaddr, nd->macaddr, 6);
438 /* Connect the phy. */
440 mdio_attach(ð->mdio_bus, ð->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);