Support for Zyxel GS1920 series (GS1920-24HP)

Might this not be cause by reply is not being correctly initialized?

When using i2cget I need to specify slave address and register I want to read (where the register address is the first byte of the data written or read). While in realtek-poe reply is declared in poe_cmd_queue as unsigned char reply[12] but never actually initialized with the i2c register on the slave we want to read.

In the example I found at https://docs.kernel.org/i2c/dev-interface.html this seems to be circumvented by using the same buffer for both write and read?

Never mind. It seems your right. I added a usleep(1000); between write and read. Which makes it quite a bit more reliable. At least the received reply with bad checksum lines are gone.

root@OpenWrt:~# ./realtek-poe -d
realtek-poe: H3K filename: /dev/i2c-4
realtek-poe: Using I2C bus #4: /dev/i2c-4
realtek-poe: Setting I2C slave address to 20
realtek-poe: I2C TX -> 20 01 ff ff ff ff ff ff ff ff ff 18
realtek-poe: RX <- 20 01 02 18 00 e1 11 11 00 01 01 40
realtek-poe: I2C TX -> 17 02 02 ff ff ff ff ff ff ff ff 13
realtek-poe: RX <- 17 02 00 ff ff ff ff ff ff ff ff 11
realtek-poe: I2C TX -> 02 03 00 ff ff ff ff ff ff ff ff fd
realtek-poe: RX <- 02 03 00 ff ff ff ff ff ff ff ff fd
realtek-poe: I2C TX -> 18 04 00 07 08 00 b4 ff ff ff ff db
realtek-poe: RX <- 18 04 00 00 ff ff ff ff ff ff ff 15
realtek-poe: I2C TX -> 13 05 7f 02 ff ff ff ff ff ff ff 92
realtek-poe: RX <- 13 05 7f 00 ff ff ff ff ff ff ff 90
realtek-poe: I2C TX -> 10 06 7f 03 ff ff ff ff ff ff ff 91
realtek-poe: RX <- 10 06 7f 00 ff ff ff ff ff ff ff 8e
realtek-poe: I2C TX -> 1a 07 00 02 01 02 02 02 03 02 ff 2e
realtek-poe: RX <- 1a 07 00 00 01 00 02 00 03 00 ff 26
realtek-poe: I2C TX -> 1c 08 00 03 01 03 02 03 03 03 ff 35
realtek-poe: RX <- 1c 08 00 00 01 00 02 00 03 00 ff 29
realtek-poe: I2C TX -> 11 09 00 01 01 01 02 01 03 01 ff 23

Verified SerDes mapping of GS1920-24 (nonPOE)

		SWITCH_PORT_SDS(0, 1, 0, qsgmii)
		SWITCH_PORT_SDS(1, 2, 0, qsgmii)
		SWITCH_PORT_SDS(2, 3, 0, qsgmii)
		SWITCH_PORT_SDS(3, 4, 0, qsgmii)
		SWITCH_PORT_SDS(4, 5, 1, qsgmii)
		SWITCH_PORT_SDS(5, 6, 1, qsgmii)
		SWITCH_PORT_SDS(6, 7, 1, qsgmii)
		SWITCH_PORT_SDS(7, 8, 1, qsgmii)

		SWITCH_PORT_SDS(8, 9, 2, qsgmii)
		SWITCH_PORT_SDS(9, 10, 2, qsgmii)
		SWITCH_PORT_SDS(10, 11, 2, qsgmii)
		SWITCH_PORT_SDS(11, 12, 2, qsgmii)
		SWITCH_PORT_SDS(12, 13, 3, qsgmii)
		SWITCH_PORT_SDS(13, 14, 3, qsgmii)
		SWITCH_PORT_SDS(14, 15, 3, qsgmii)
		SWITCH_PORT_SDS(15, 16, 3, qsgmii)

		SWITCH_PORT_SDS(16, 17, 4, qsgmii)
		SWITCH_PORT_SDS(17, 18, 4, qsgmii)
		SWITCH_PORT_SDS(18, 19, 4, qsgmii)
		SWITCH_PORT_SDS(19, 20, 4, qsgmii)
		SWITCH_PORT_SDS(20, 21, 5, qsgmii)
		SWITCH_PORT_SDS(21, 22, 5, qsgmii)
		SWITCH_PORT_SDS(22, 23, 5, qsgmii)
		SWITCH_PORT_SDS(23, 24, 5, qsgmii)

		SWITCH_PORT_SDS(48, 25, 12, qsgmii)
		SWITCH_PORT_SDS(49, 26, 12, qsgmii)
		SWITCH_PORT_SDS(50, 27, 12, qsgmii)
		SWITCH_PORT_SDS(51, 28, 12, qsgmii)

Totally forgot those unfinished fragments ... save them for posterity before dropping the build environment ...

Minimum RLT839x 10G SerDes initialization sequence to get QSGMII PHY link up and running and compensate for missing U-Boot.

	... somehwere early in the PCS driver ...

	if (sds != 8 && sds !=9 && sds != 12 && sds != 13)
		return;
	
	rtpcs_sds_write(ctrl, sds, 0x0a, 0x1c, 0x002a);
	rtpcs_sds_write(ctrl, sds, 0x0a, 0x1d, 0x0000);
	rtpcs_sds_write(ctrl, sds, 0x0a, 0x1e, 0xa052); /* changes to 0x0002 */
	rtpcs_sds_write(ctrl, sds, 0x0a, 0x1f, 0x9a00); /* changes to 0xbe00 */
	rtpcs_sds_write(ctrl, sds, 0x0b, 0x00, 0x00f5);
	rtpcs_sds_write(ctrl, sds, 0x0b, 0x01, 0xc480);
	rtpcs_sds_write(ctrl, sds, 0x0b, 0x05, 0x3340);
	rtpcs_sds_write(ctrl, sds, 0x0b, 0x08, 0x803f);
	rtpcs_sds_write(ctrl, sds, 0x0b, 0x0c, 0x2bff);
	rtpcs_sds_write(ctrl, sds, 0x0b, 0x0d, 0x2bff);
	rtpcs_sds_write(ctrl, sds, 0x0b, 0x11, 0x0000);
	
	if (even) {
		rtpcs_sds_write(ctrl, sds, 0x0a, 0x11, 0xf04a);
		rtpcs_sds_write(ctrl, sds, 0x0b, 0x04, 0x39ff);
		rtpcs_sds_write(ctrl, sds, 0x0b, 0x06, 0x40a2);
		rtpcs_sds_write(ctrl, sds, 0x0b, 0x0e, 0x4e10); /* changes to 0x0a10 */
	} else {
		rtpcs_sds_write(ctrl, sds, 0x0a, 0x11, 0xfdab);
		rtpcs_sds_write(ctrl, sds, 0x0b, 0x04, 0x93fa);
		rtpcs_sds_write(ctrl, sds, 0x0b, 0x06, 0x4280);
		rtpcs_sds_write(ctrl, sds, 0x0b, 0x0e, 0x4c50); /* changes to 0x0a10 */
	}

	/* Needs this function from RTK afterwards */
	rtl839x_serdes_reset(sds);

Minimum RTL8214FC initialization sequence to get network connectivity and to compensate for missing U-Boot. Should work on RTL838x too.

static int rtl8214fc_config_init(struct phy_device *phydev)
{
	static int regs[] = {16, 19, 20, 21};

	if (phydev->mdio.addr % 8)
		return 0;
	...
	for (port = 0; port < 4; port++)
		patchphy = get_package_phy(phydev, port);		

		phy_write(phydev, 0x1e, 0x8);
		/* setup basic fiber control in base phy and default to copper */
		phy_write_paged(phydev, 0x266, regs[port], 0x0f95};
		phy_write(phydev, 0x1e, 0x0);	

		phy_write(patchphy, 0x1e, 0x3);
		/* set fiber SerDes RX to negative edge */
		phy_modify_paged(patchphy, 0x8, 0x17, BIT(14), 0);
		/* auto negotiation disable link on */
		phy_modify_paged(patchphy, 0x8, 0x14, 0, BIT(2));
		/* disable fiber 100MBit */
		phy_modify_paged(patchphy, 0x8, 0x17, BIT(5), 0);
		phy_write(patchphy, 0x1e, 0x0);

		/* Disable EEE. 0xa5d/0x10 is the same as MDIO_MMD_AN / MDIO_AN_EEE_ADV */
		phy_write_paged(patchphy, 0xa5d, 0x10, 0x0000);
	}

	/* similar hardware, reuse for MAC SerDes init */
	rtl8218b_config_init(phydev); 
	...

Seems to work on the PoE model as well. I added it to my dts and created a PR at https://github.com/openwrt/openwrt/pull/20439

The LED situation on the RTL838x target hasn't changed, right? On my model, the PoE lights are active instead of the port LEDs.

I booted it on GS2210-8HP with added rtl8214fc_config_init.

It comes up with ports 1-8 as lan1-8 and port 9/10 as lan25,26

Connecting port 9/10 with RJ45 brings the link up. Connecting them with a DAC reads the EEPROM switches between RJ45/SFP, but checking with ethtool its not seeing the other end advertise capabilities.

I had a look at this. RTL839x works similar to RTL93XX, using LED sets which define the LED behavior. I have a dirty patch for this, could clean it up and submit it in the next days.

But it doesn’t solve the behavior on the GS1920-24HP for now. Still have to figure out how to properly configure it then. On my v2, the front panel PCB has two RTL8231 in shift register mode, and three HC164 shift registers which are wired up in serial like “RTL8231 –> RTL8231 –> HC164 –> HC164 –> HC164”. I’m not sure yet how the LEDs are connected to this. At least configuring the LEDs with my patch, the LEDs with the correct port number light up although it’s currently both the LINK/ACT and PoE LEDs.
Important to note here is that the LEDs for the combo ports are not controlled by the SoC (and therefore have to be excluded from configuration). Instead they are managed by the RTL8214FC. Not sure if this needs to be configured too or should work by default.

Moreover, I worked on my GS1920-24HPv2 and figured out it’s quite more different than expected in the first place. Most important differences I’ve seen so far:

  • RTL8391M SoC (instead of RTL8392M)
  • 256MiB RAM, 32MiB Flash (definitely needs a separate recipe in OpenWrt)
  • RTL8214FC PHYs connected at port numbers 24-27 (instead of 48-51). Most likely due to the different SoC variant. I’m not sure if this only applies to the SMI address or also to the “MAC number”. In my case, the RTL8214FC PHYs are only recognized at these addresses right now but link isn’t detected.
  • Slightly different GPIOs for SFPs: cages 25 and 26 share SCL on GPIO3, cages 27 and 28 use different SCL GPIOs than v1
  • no ADT7468 fan controller, LM96000 on PCB
  • serial console: simple TTL UART, accessible without opening the case

Some progress!
With some help I was able to make a proper sniff/trace of the i2c communication during boot of my GS2210 using a logic analyzer at the local hackerspace. (And in the process documenting usage of that beast of an analyzer).

To test, I filtered all read/writes going to slave 0x20 and converted it to a script executing i2cget/set commands. After executing this script, I'm now looking at a running PoE powered Rasberry Pi running of my switch. :partying_face:

I'll try to upload and link the raw trace and resulting script I used somewhere. (Any suggestions where I can easily share these files? Can I share them via the forum somehow?)

The replay script I used
Pulseview session

My GS1920-24HPv2 has no serial connector on the outside. Are you talking about another switch?

It’s not directly outside on the switch. If you have the switch facing with the ports to you, look at it’s right side and you should find a rectangular opening within the regular honeycomb structure. Through that opening you should see a pin header. It’s a bit fiddly but doable without opening the case.

similar to https://community.zyxel.com/en/discussion/comment/39133/#Comment_39133 ?

Similar, just that on GS1920-24HPv2 it’s horizontal. But Zyxel seems to make serial available like that for most of their “newer” revisions of switches.

Is the GS1920-24HPv2 TTY level 3.3V or 5.6V? I’m just not sure which version the 5.6V was referring to.

It’s 3.3V. The ±5.6V is just for v1 because it uses RS232 instead of TTL.

Would you have any use for console output from the switch with zyxel firmware and PoE errors? I collected some.

Can the v1 be set via console to boot from the first image?

As I have one and I think that I've bricked the management part after one too many resets (not sure, long story).

If you have access to BootExt, yes. Interrupt boot as described above and use the command ATGI. According to my notes, ATGI1 selects the first image and ATGI2 the second one.

If that doesn't work, you can always restore the switch with the built-in recovery procedure and an xmodem transfer (also described above).

@plappermaul Can this be taken as-is and should work? I kept putting off moving the small pieces of RTL839X SerDes setup to the PCS driver for several reasons. And I’m not in a good position to test this, on my GS1920-24HPv2 both snippets don’t seem to make any difference, i.e. the device doesn’t even use SDS 8, 9, 12, 13 and in both cases, only the RTL8214FC copper ports work, not the fiber ports.

I’m fine with taking the first snippet, add the reset function from the SDK and use that for transition, hoping it doesn’t break anything. And I have to rely on others for testing this then with appropriate devices.

The GS1920 drives the RTL8214FC by SerDes 12. See https://github.com/openwrt/openwrt/pull/20439 I developed the patches above with the DTS from that PR and a GS1920-24 (non POE).

To be sure that I understand you correctly.

  • Did you make use of rtl839x_serdes_reset() from the SDK after SerDes init?
  • Do the RTL8214FC ports work at all without these SDS/PHY sequences?
  • What is the difference with these patches applied?

The GS1920-24HPv2 is quite different, using RTL8391M instead of RTL8392M, having the RTL8214FC on SerDes 6 and GMACs 24-27. Ultimately verified this when manually changing the bits for SerDes 6 in MAC_SERDES_IF_CTRL, killing the RTL8214FC ports when setting another value than 6.

Well, kind of. I took the function from the SDK and translated the register writes to our page+reg representation (hopefully correct). Then I took your snippet for 10G initialization, but as it only applies to SerDes 8, 9, 12, 13, it doesn’t run for any usable SerDes on my device. So the SerDes reset doesn’t run for the SerDes 6. When I change that so the reset is run for all SerDes, it still seems to work but somehow kills SerDes 0, 2, 4 so that only half of the normal copper ports actually work. The RTL8214FC copper ports still work though.

Only the copper ports. The fiber ports don’t detect the link with a SGMII 1G-T module. But yes, that all works with plain trunk. And no, this device doesn’t run U-boot, just BootBase + BootExt.

I don’t see any so far.

EDIT: It seems like a proper QSGMII configuration on SerDes 0-7 is the default when the SoC starts, so it maybe works out of the box because of this?

EDIT2: https://github.com/jonasjelonek/openwrt/commits/realtek/gs1920-24hp-v2/ to see what I’m working with.