[BPI-R4] Zyxel PMG3000-D20B SFP module not detected

I bought a PMG3000-D20B SFP module, since I need that for my GPON Fiber uplink. However, the module is not detected whatsoever.

In dmesg, with debugging turned on, sometimes this appears while inserting it:

[Wed Jul  3 19:23:08 2024] sfp sfp1: mod-def0 0 -> 1
[Wed Jul  3 19:23:08 2024] sfp sfp1: SM: enter empty:up:down event insert
[Wed Jul  3 19:23:08 2024] sfp sfp1: SM: exit probe:up:down
[Wed Jul  3 19:23:08 2024] sfp sfp1: mod-def0 1 -> 0
[Wed Jul  3 19:23:08 2024] sfp sfp1: SM: enter probe:up:down event remove
[Wed Jul  3 19:23:08 2024] sfp sfp1: module removed
[Wed Jul  3 19:23:08 2024] sfp sfp1: SM: exit empty:up:down

The status LED of the mainboard briefly flashes bright green while pushing in the module, and then settles for a very dim green glow while the module is in. When pulling it out, it very briefly flashes bright green as well. I can also fiddle with the module to hold it at the point where it’s bright green. It stays bright then the whole time, but nothing else changes. Notably, above debug messages also scrolls through when I only push it in up to that point.

I can however successfully talk to the module via i2cdump:

# i2cdump -y 3 0x50
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 03 04 01 00 00 00 02 00 00 00 00 03 0c 00 14 c8    ???...?....??.??
10: 00 00 00 00 5a 59 58 45 4c 00 00 00 00 00 00 00    ....ZYXEL.......
20: 00 00 00 00 00 00 00 00 50 4d 47 33 30 30 30 2d    ........PMG3000-
30: 44 32 30 42 00 00 00 00 56 31 2e 30 05 1e 00 55    D20B....V1.0??.U
40: 00 1a 00 00 53 32 33 34 31 30 37 35 30 32 35 39    .?..S23410750259
50: 36 00 00 00 31 35 30 35 32 35 20 20 68 f0 01 a4    6...150525  h???
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................

When manually trying to bring the link up, this is logged:

[  448.515127] sfp sfp1: SM: enter empty:up:down event dev_down
[  448.520845] sfp sfp1: SM: exit empty:down:down
[  450.753154] mtk_soc_eth 15100000.ethernet eth2: configuring for inband/sgmii link mode
[  450.761141] mtk_soc_eth 15100000.ethernet eth2: major config sgmii
[  450.767314] mtk_soc_eth 15100000.ethernet eth2: phylink_mac_config: mode=inband/sgmii/none adv=00,00000010,00000200,00026260 pause=00
[  450.782875] sfp sfp1: SM: enter empty:down:down event dev_up
[  450.788550] sfp sfp1: SM: exit empty:up:down

ethtool reports:

# ethtool eth2
Settings for eth2:
        Supported ports: [ MII ]
        Supported link modes:   10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Half 1000baseT/Full
                                10000baseT/Full
                                2500baseX/Full
                                1000baseKX/Full
                                10000baseKX4/Full
                                10000baseKR/Full
                                10000baseR_FEC
                                1000baseX/Full
                                10000baseCR/Full
                                10000baseSR/Full
                                10000baseLR/Full
                                10000baseLRM/Full
                                10000baseER/Full
                                2500baseT/Full
                                5000baseT/Full
                                100baseT1/Full
                                1000baseT1/Full
                                100baseFX/Half 100baseFX/Full
                                10baseT1L/Full
                                10baseT1S/Full
                                10baseT1S/Half 10baseT1S_P2MP/Half
        Supported pause frame use: Symmetric Receive-only
        Supports auto-negotiation: Yes
        Supported FEC modes: Not reported
        Advertised link modes:  1000baseT/Full
                                1000baseKX/Full
                                1000baseX/Full
                                1000baseT1/Full
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes
        Advertised FEC modes: Not reported
        Speed: Unknown!
        Duplex: Unknown! (255)
        Auto-negotiation: on
        Port: MII
        PHYAD: 0
        Transceiver: internal
        Current message level: 0x000000ff (255)
                               drv probe link timer ifdown ifup rx_err tx_err
        Link detected: no
# ethtool -m eth2
netlink error: No such device

I tried manually setting the speed of the module to 1Gbit full duplex, but to no avail. Is this module just electrically incompatible? Or is this just a missing driver quirk?

The kernel in use is 6.9-main from GitHub - frank-w/BPI-Router-Linux at 6.9-main with latest stable linux 6.9.7 merged into it. Also tried with 6.9.0 as it is in that repo, but that changed nothing either.

Ok, I have managed to make this module at least work. The issue from my observation: It has a really long boot-up sequence, and only AFTER that sequence, it pulls the MOD_DEF0 pin low.

The problem: While that pin is not pulled low, the circuit of the BPI-R4 board itself does not turn on the power supply for the SFP module. There’s a mosfet that prevents it.

See the circuit diagram:

I’ve marked the critical spot. The mosfet there will stay off until the module signalizes that it’s present/ready. But this particular module won’t do that until it had power for about a minute.

I verified this by manually poking wires at the board, bridging over the mosfet, manually energizing the module. After holding this for a while, I could let go of the bridge, and it held itself on and is working as expected now.

So this seems like quite a fundamental design flaw of the BPI-R4? Or is this module violating some kind of spec by behaving like that? In any case, judging by the circuit diagram, there is a spot there for just a 0-Ohm bridge instead of the mosfet, so I guess I’ll have to look into some fine soldering, or just soldering in a small bridge over the existing mosfet.

Edit: There is this ominous 3.3V_SFP1 thing directly to the right of the mosfet. It does not seem to go anywhere. It does not appear anywhere else in the entire circuit diagram. If this could be somehow switched on in software, it’d save me an arduous soldering job. But there is no documentation on it.

Ok, so I actually got out the soldering iron, and replaced the SFP1 mosfet with just a direct bridge from S to O:

Result: LED is always lit, even without module. But when inserting the module:

[ 5068.554425] sfp sfp1: mod-def0 0 -> 1
[ 5068.558101] sfp sfp1: SM: enter empty:up:down event insert
[ 5068.563580] sfp sfp1: SM: exit probe:up:down
[ 5068.567925] sfp sfp1: mod-def0 1 -> 0
[ 5068.571589] sfp sfp1: SM: enter probe:up:down event remove
[ 5068.577078] sfp sfp1: module removed
[ 5068.580645] sfp sfp1: SM: exit empty:up:down
[ 5126.541457] sfp sfp1: mod-def0 0 -> 1
[ 5126.545155] sfp sfp1: SM: enter empty:up:down event insert
[ 5126.550636] sfp sfp1: SM: exit probe:up:down
[ 5126.854093] sfp sfp1: SM: enter probe:up:down event timeout
[ 5126.871010] sfp sfp1: module ZYXEL PMG3000-D20B rev V1.0 sn S234107502596 dc 150525
[ 5126.878869] mtk_soc_eth 15100000.ethernet eth2: optical SFP: interfaces=[mac=2-4,22-24,27,29, sfp=22]
[ 5126.888106] mtk_soc_eth 15100000.ethernet eth2:  interface 22 (1000base-x) rate match none supports 6,10,13-14,41
[ 5126.898389] mtk_soc_eth 15100000.ethernet eth2: optical SFP: chosen 1000base-x interface
[ 5126.906480] mtk_soc_eth 15100000.ethernet eth2: requesting link mode inband/1000base-x with support 00,00000000,00000200,00006440
[ 5126.918133] mtk_soc_eth 15100000.ethernet eth2: switched to inband/1000base-x link mode
[ 5126.926147] mtk_soc_eth 15100000.ethernet eth2: major config 1000base-x
[ 5126.933304] mtk_soc_eth 15100000.ethernet eth2: phylink_mac_config: mode=inband/1000base-x/none adv=00,00000000,00000200,00006440 pause=04
[ 5126.945759] mtk_soc_eth 15100000.ethernet: mux mux_gdm1_to_gmac1_esw isn't present on the SoC
[ 5126.954291] mtk_soc_eth 15100000.ethernet: mux mux_gmac2_gmac0_to_gephy isn't present on the SoC
[ 5126.963065] mtk_soc_eth 15100000.ethernet: mux mux_u3_gmac2_to_qphy isn't present on the SoC
[ 5126.971502] mtk_soc_eth 15100000.ethernet: mux mux_gmac1_gmac2_to_sgmii_rgmii isn't present on the SoC
[ 5126.980805] mtk_soc_eth 15100000.ethernet: mux mux_gmac12_to_gephy_sgmii isn't present on the SoC
[ 5126.989683] mtk_soc_eth 15100000.ethernet: path gmac3_sgmii in set_mux_gmac123_to_gephy_sgmii updated = 1
[ 5126.999250] mtk_soc_eth 15100000.ethernet: path gmac3_sgmii in set_mux_gmac123_to_usxgmii updated = 0
[ 5127.012020] sfp sfp1: tx disable 1 -> 0
[ 5127.015892] sfp sfp1: SM: exit present:up:wait
[ 5127.020395] sfp sfp1: los 0 -> 1
[ 5127.023625] sfp sfp1: SM: enter present:up:wait event los_high
[ 5127.029465] sfp sfp1: SM: exit present:up:wait
[ 5127.037459] hwmon hwmon3: temp1_input not attached to any thermal zone
[ 5127.084076] sfp sfp1: SM: enter present:up:wait event timeout
[ 5127.089840] sfp sfp1: SM: exit present:up:wait_los

So it actually works now without having to poke around with wires on the board!

I’m still curious why the decision to put this mosfet-circuit there was made? The BPI-R3 did not have it, any any reference design I can find has nothing like it. If at all, it could be used for the status led, so it’d follow the module status.

2 Likes

Could you please share how you got the verbose dmesg debug messages?
I am trying to get the exact same scenario to work, but for me dmesg only ever prints out:

[ 1066.097849] sfp sfp1: module removed

Having those debug messages would be extremely helpful when I do the exact same solder mod to my board.

Also shouldn’t it be possible to permanently power the SFP ports by pulling that GPIO low that is connected to the gate of the MOSFET?

Finally, am I interpreting it correctly that there are two resistors between SFPX_MOD_DEF0 and 3.3VD one 47k and one 4.7k ?

Isn’t that a test-point?

The mod-def0 is supposed to be an input (on R4 side), so I do not think we’re supposed to set it as output and make it low. Although there is a 1k resistor between the 2, so the current would be limited.

Instead of soldering on the R4, I think is would be easier and safer to open the sfp module and solder the mod-def0 pin to ground…

That makes a ton of sense, thanks a lot for replying so quickly :slight_smile:

Soldering the SFP module probably the safer option since it is only 40€ compared to the 120ish for the R4. It isn’t even necessary to open it up, the part shown in your picture is exposed by default. But the components are also much smaller and I am really bad at microsoldering.

I will try one of the two solutions this Wednesday and post my results here.

Again, thanks a lot for your reply :slight_smile:

Also I believe the electronics on R4 are designed to support hotplugging (the power) so I wouldn’t hotplug if that short is made on R4… You could kill both R4 and module…

That is not gonna work. The OS on the SFP module needs to boot first, and does not pull the pin to ground until it is up and running. Until it’s up, the emulated EEPROMs don’t exist, and the module will plain fail to be recognized. Since the SFP driver looks at the status of the def0 pin to determine if there’s a module or not, manually grounding it would remove the chips ability to signal “ready”.

The circuit diagram for the BPI-R4 clearly intents for there to be just a bridge instead of the mosfet, so I’m pretty sure replacing it is fine. All it does is permanently power the SFP module (and the status LED), instead of tieing power to def0 being pulled low by the module.

The board sees no difference compared to the mosfet being there. I’ve replugged the module plenty of times with no ill effects. 500mA 3.3V is not gonna arc on you or anything.

The mod-def0 signal should be pulled to ground by the module. So it is easy to add this with 1 wire in the module.

Charged capacitors may not be suddenly connected to uncharged capacitors. This is what the mosfet prevents, together with the R/C combination.

When the module is inserted, first ground and 3.3v pins are connected, the copper fingers are longer. Inserting furter, then mod-def0 is connected, activating the charging of the capacitors of the module. The R/C combination opens the mosfet relatively slowly. Thereby hotplugging the module is safe.

The module is not ready on insertion, it runs Linux with OpenWRT, so it needs 20~30 seconds to boot. It only pulls def0 low once it’s done booting. And before it’s booted, all communication with it will fail.

So bridgeing def0 to ground manually will make the board try to talk to the module before it’s booted, which will cause all kinds of bad issues, and will likely end up with the kernel concluding the module is broken before it has a chance to boot and operate.

For that, should use a quirk with sfp_fixup_long_startup

https://elixir.bootlin.com/linux/v6.10.7/source/drivers/net/phy/sfp.c#L343

So shorting the mosfet will trick the system in making it think it is inserted at the moment it is booted. Will work, but hotplugging would be unsafe.

Shouldn’t there be pads somewhere for those missing bridge resistors, R102 and R127?

They are under the mosfet, which indicates to me that briding it was very much intended.

Hi people,

I want to use my BPI R4 with the Telekom (Germany) Branded Zyxel PMG3000-DB20B SFP. I installed the snapshot-openwrt image on the SD-Card and insterted the SFP after it arrived. First nothing appeared in dmesg but the notice when i remove the module.

After bridging the MOSFET it got recognised, but nothing more than that. I dont have any PHY devices and cant bring up the eth2 manually.

So i just wanted to ask: What did you do to get it working?

Thanks in advance.

Nothing really, once the module gets its power, it takes some 20~30 seconds to boot up, and then it just works. Keep in mind that you need special VLAN setups for some providers, like the Telekom. And you also need to tell them the SN of your module, or ssh into the module and change it to the one you already have registered.

Does this help?

If it’s Telekom, there is no DHCP. You need to do PPPoE on VLAN 7 once the GPON link is established. The link of the interface itself should eventually come up on its own, and you can then manually assign a static IP to it and ssh into the OpenWRT on the SFP module to change setting/SN/… To go online, you add a VLAN interface for VLAN 7 on top, and then do PPPoE with your provided credentials. For IPv6, you then do DHCPv6 PD on top of the established PPPoE link.

The Module is actually already configured to the Telekom side. And i configured the network like this:

config interface 'sfp'
	option proto 'static'
	option ipaddr '10.10.1.2'
	option netmask '255.255.255.0'
	option gateway '10.10.1.1'
	option device 'eth2.7'
config vlan
	option device 'eth2'
	option vid '7'

In dmesg i find only these lines regarding sfp and eth2:

[   10.506008] sfp sfp1: Host maximum power 3.0W
[   10.510860] sfp sfp2: Host maximum power 3.0W
[   10.832644] sfp sfp2: module ZYXEL PMG3000-D20B rev V1.0 sn S234107503784 dc 150525
[    4.724506] mtk_soc_eth 15100000.ethernet eth2: mediatek frame engine at 0xffffffc082900000, irq 103
[   13.575165] mtk_soc_eth 15100000.ethernet eth2: configuring for inband/10gbase-r link mode