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
);