Vlad Lazarenko

... making all this up as I go along

Marvell 88E1111 Reset Sequence

If you are one of the lucky owners of one of the Altera’s development kits with Marvell’s software-programmable 88E1111 Ethernet PHY then you know it’s a bitch. The problem is not really in a PHY itself — it’s not a bad piece of hardware at all. The problem is that Altera provides literally zero support or documentation with it. Go figure.

As it turns out, the PHY’s default settings after the hardware reset is to work in center-aligned mode, whereas the default mode for FPGA data-transfers is edge-aligned. On top of that, some kits have a bug and the PHY must be reset two or three times in order to become operational.

The quick fix to get the I/O between FPGA and the PHY working without software-programming the PHY is to shift the clock 90°. That can be done with PLL. There are two problems with this approach however —it makes it a lot harder to time-constrain the design and it introduces an extra clock while the PHY is fully capable of working in edge-aligned mode. If only you knew how to set it up…

As it turned out, the only way to get the documentation for the PHY is to sign an NDA with Marvell. It sounds as ridiculous as the need to sign a NDA in order to get an owner’s manual for the car you have just bought. I didn’t want to do it and “picked the red pill.” ¡No pasarán!

After a few hours of searching through the darkest corners of the forum archives and reading a somewhat messy Altera’s Triple-Speed Ethernet drivers code, I finally came up with a piece of magic that properly resets the PHY and makes it use edge-aligned clock. It assumes that “base” is a memory address of the MAC’s MDIO space (see Table 6-1 of the TSE User Guides for details), a user-space Linux running on x86_64 (though can be easily ported to kernel mode):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#define PHY_CTRL_REG 0x00
#define PHY_AUTO_NEG 0x04
#define PHY_AUTO_NEG 0x04
#define PHY_1000BASE_T_CONTROL 0x09
#define PHY_SPEC_CONTROL 0x10
#define PHY_SPEC_STATUS 0x11
#define PHY_SPEC_CONTROL_EXT 0x14
#define PHY_SPEC_STATUS_EXT 0x1B

#define mb() asm volatile ("": : :"memory")
#define rmb() mb()
#define wmb() mb()

static void phy_sw_reset(uint32_t *base)
{
    uint32_t ctrl;

    ctrl = base[PHY_CTRL_REG];
    rmb();
    base[PHY_CTRL_REG] = ctrl | 0x8000;
    wmb();
}

int marvell_reset(uint32_t *base)
{
    uint32_t v;

    /* Initialize Control (REG 0) */
    v = base[PHY_CTRL_REG];
    rmb();

    v &= 0x8EBF; /* Reset */
    v |= 0x0040; /* Enable Speed 1000 */
    v |= 0x0100; /* Enable Full Duplex Mode */
    base[PHY_CTRL_REG] = v;
    wmb();

    phy_sw_reset(base);

    /* AN Advertisement Register (REG 4) */
    v = base[PHY_AUTO_NEG];
    rmb();

    base[PHY_AUTO_NEG] = v & 0xFE1F;
    wmb();
    phy_sw_reset(base);

    /* 1000BASE-T Control Register (REG 9) */
    v = base[PHY_1000BASE_T_CONTROL];
    rmb();
    base[PHY_1000BASE_T_CONTROL] = v & 0xFCFF;
    wmb();
    phy_sw_reset(base);

    /* PHYSpecific Control Register (REG 16).
       Set PHY Synchronizing FIFO to maximum */
    v = base[PHY_SPEC_CONTROL];
    rmb();

    base[PHY_SPEC_CONTROL] = v | 0xC000;
    wmb();
    phy_sw_reset(base);

    /* Extended PHYSpecific Status Register (REG 27).
       Set PHY HWCFG_MODE for RGMII to Copper. */
    v = base[PHY_SPEC_STATUS_EXT];
    rmb();
    base[PHY_SPEC_STATUS_EXT] = v | 0x000B;
    wmb();
    phy_sw_reset(base);

    /* Extended PHYSpecific Control Register (REG 20).
       Enable RGMII TX and RX Timing Control. */
    v = base[PHY_SPEC_CONTROL_EXT];
    rmb();

    /* Bring it up */
    v &= 0xFF7D;
    v |= 0x0082;
    base[PHY_SPEC_CONTROL_EXT] = v;
    wmb();
    phy_sw_reset(base);

    return 0;
}

Some of the logic and magic masks I dug out of the TCL script written for JTAG System Console that I stumbled upon in a N647_TSE_Single_Port_RGMI_Dev_AIIGX_ACDS reference design.

Hope it helps!