diff --git a/cmd_parser.c b/cmd_parser.c
index 2bc5595..9f72df4 100644
--- a/cmd_parser.c
+++ b/cmd_parser.c
@@ -662,6 +662,14 @@ void parse_port(void)
else if (cmd_compare(3, "full"))
phy_settings.duplex = PHY_DUPLEX_FULL;
phy_set_speed();
+ } else if (cmd_compare(2, "10g")) {
+ print_string(" 10G\n");
+ phy_settings.speed = PHY_SPEED_10G;
+ phy_set_speed();
+ } else if (cmd_compare(2, "5g")) {
+ print_string(" 5G\n");
+ phy_settings.speed = PHY_SPEED_5G;
+ phy_set_speed();
} else if (cmd_compare(2, "2g5")) {
print_string(" 2.5G\n");
phy_settings.speed = PHY_SPEED_2G5;
@@ -1063,6 +1071,9 @@ void parse_eee(void)
__xdata int8_t port = -1;
__xdata uint8_t speed = EEE_2G5;
__xdata uint8_t speed_word = 0;
+
+ if (machine.n_10g)
+ speed = EEE_10G;
// Check if word 2 is a speed (contains 'g' or 'm') or a port number
if (cmd_words_len >= 3) {
uint8_t idx = cmd_words_b[2];
diff --git a/doc/devices/ZX310S-4T2XH.md b/doc/devices/ZX310S-4T2XH.md
new file mode 100644
index 0000000..96f9d57
--- /dev/null
+++ b/doc/devices/ZX310S-4T2XH.md
@@ -0,0 +1,59 @@
+# ZX310S-4T2XH/
+
+The following is a documentation for the managed switch marked as `ZX310S-4T2XH`
+and sold by Horaco.
+
+The original software is running UART on 57600 baud rate. The solder holes
+of the UART header are filled in. In order to install a UART header, they
+need to be cleared first. A 1.2mm drill can be used, alternatively a
+de-soldering wick.
+The original firmware uses 57600 baud 8N1
+
+CPU: RTL8372
+Flash: 2MByte Winbond W25Q16DV (U3)
+PHY RTL8261BE
+
+### Label specifications
+
+- **Name**:
+- **Ports**:
+ - 4 × RJ45: 10/100/1000/2500 Mbps
+ - 1 x RJ45: 10/100/1000/2500/5000/10000 Mbps
+ - 1 × SFP+: 1000 / 2500 / 10000 Mbps
+- **Power**: 12V DC, 2A barrel connector
+
+
+
+### What works
+The device is fully supported:
+- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
+- The 10GBit port works. TODO: Fix EEE, speed selection
+- The SFP+ port supports 1G, 2.5G and 10G modules
+- LEDs work with the same indiciations as the OEM firmware
+
+### PCB overview
+
+**Board markings**
+- Top silkscreen: PCB-SL310S-4T1T1X-V1.0.1-24107
+
+Top side
+
+
+
+Bottom
+
+
+
+### J1, serial console
+
+| `J1` pin | Signal |
+| -------- | ----------- |
+| 1 | TX (Output) |
+| 2 | RX (Input) |
+| 3 | GND |
+| 4 | 3V3 |
+
+
+## Power supply
+
+Input power is delivered via barell plug, `12V 2A` adapter was provided.
diff --git a/doc/devices/photos/ZX310S-4T2XH/label.jpg b/doc/devices/photos/ZX310S-4T2XH/label.jpg
new file mode 100644
index 0000000..88c1303
Binary files /dev/null and b/doc/devices/photos/ZX310S-4T2XH/label.jpg differ
diff --git a/doc/devices/photos/ZX310S-4T2XH/pcb_bottom.jpg b/doc/devices/photos/ZX310S-4T2XH/pcb_bottom.jpg
new file mode 100644
index 0000000..5d99f8a
Binary files /dev/null and b/doc/devices/photos/ZX310S-4T2XH/pcb_bottom.jpg differ
diff --git a/doc/devices/photos/ZX310S-4T2XH/pcb_top.jpg b/doc/devices/photos/ZX310S-4T2XH/pcb_top.jpg
new file mode 100644
index 0000000..0e579a2
Binary files /dev/null and b/doc/devices/photos/ZX310S-4T2XH/pcb_top.jpg differ
diff --git a/html/main.js b/html/main.js
index 8e50017..08499af 100644
--- a/html/main.js
+++ b/html/main.js
@@ -164,7 +164,9 @@ function update(callback) {
} else {
psvg.style.opacity = 1.0;
pState[n] = p.link;
- if (p.link == 4 || p.link == 5 || p.link == 6) {
+ if (p.link == 5 || p.link == 7) {
+ leds[0].style.fill = "green"; leds[1].style.fill = "blue";
+ } else if (p.link == 4 || p.link == 6) {
leds[0].style.fill = "green"; leds[1].style.fill = "orange";
} else if (p.link == 1 || p.link == 2 || p.link == 3) {
leds[0].style.fill = "green"; leds[1].style.fill = "green";
diff --git a/httpd/page_impl.c b/httpd/page_impl.c
index e9f8082..0010063 100644
--- a/httpd/page_impl.c
+++ b/httpd/page_impl.c
@@ -248,14 +248,16 @@ void send_basic_info(void)
slen += strtox(outbuf + slen, "\",\"flash_size\":\"");
string_to_html(get_flash_size_str());
- slen += strtox(outbuf + slen, "\",\"sfp_slot_0\":\"");
- send_sfp_info(0);
- char_to_html('"');
- if (machine.n_sfp == 2) {
- slen += strtox(outbuf + slen, ",\"sfp_slot_1\":\"");
- send_sfp_info(1);
- char_to_html('"');
+ if (machine.n_sfp) {
+ slen += strtox(outbuf + slen, "\",\"sfp_slot_0\":\"");
+ send_sfp_info(0);
+ if (machine.n_sfp == 2) {
+ slen += strtox(outbuf + slen, "\",\"sfp_slot_1\":\"");
+ send_sfp_info(1);
+ }
}
+ char_to_html('"');
+
char_to_html('}');
}
diff --git a/machine.c b/machine.c
index 2e6bb4b..24fcbd3 100644
--- a/machine.c
+++ b/machine.c
@@ -544,7 +544,6 @@ __code const struct machine machine = {
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
-
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
@@ -571,6 +570,51 @@ __code const struct machine machine = {
void machine_custom_init(void) { }
+#elif defined MACHINE_ZX310S_4T2XH
+__code const struct machine machine = {
+ .machine_name = "ZX310S-4T2XH",
+ .isRTL8373 = 0,
+ .min_port = 3,
+ .max_port = 8,
+ .n_sfp = 1,
+ .n_10g = 1,
+ .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
+ .phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
+ .is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
+ .sfp_port[0].pin_detect = GPIO38,
+ .sfp_port[0].pin_los = GPIO_NA,
+ .sfp_port[0].pin_tx_disable = GPIO_NA,
+ .sfp_port[0].sds = 1,
+ .sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
+ .reset_pin = GPIO48_I2C_SCL1,
+ .high_leds = { .mux = LED_28_SYS, .enable = LED_27 | LED_28_SYS | LED_29 },
+ .led_mux_custom = 1,
+ .led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08, // 65e0
+ 0x09, 0x0c, 0x3f, 0x0d, 0x10, // 65e4
+ 0x11, 0x0e, 0x14, 0x11, 0x12, // 65e8
+ 0x15, 0x15, 0x16, 0x18, 0x19, // 65ec
+ 0x1a, 0x19, 0x1d, 0x1e, 0x1c, // 65f0
+ 0x1d, 0x20, 0x21 },
+ .port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
+ /* Ports 1-4: Orange: 2.5GBit, Green: 10/100/1000MBit
+ * Port 5: Blue: 10GBit, Green: 10Mbit-5GBit
+ * SFP-port: Blue: 10GBit, Green 100MBit-5GBit
+ */
+ .led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT,
+ LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
+ LEDS_DUPLEX,
+ LEDS_2G5 | LEDS_LINK | LEDS_ACT },
+ {
+ LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT | LEDS_5G,
+ LEDS_LINK | LEDS_ACT | LEDS_10G,
+ LEDS_2G5 | LEDS_LINK,
+ LEDS_COL | LEDS_DUPLEX
+ }
+ },
+};
+
+void machine_custom_init(void) { }
+
#else
#error "Please select a machine type in machine.h"
#endif
diff --git a/machine.h b/machine.h
index 8ae0334..d7daa96 100644
--- a/machine.h
+++ b/machine.h
@@ -20,6 +20,7 @@
// #define MACHINE_HI_K0402WS
// #define MACHINE_K0501W_V2_0
// #define MACHINE_LIANGUO_ZX_SWTGW215AS
+// #define MACHINE_ZX310S_4T2XH
// #define MACHINE_DEFAULT_8C_1SFP
typedef struct {
@@ -58,6 +59,7 @@ typedef struct machine {
// Highest logical port number
uint8_t max_port;
uint8_t n_sfp;
+ uint8_t n_10g;
uint8_t log_to_phys_port[9];
uint8_t phys_to_log_port[9]; // Starts at 0 for port 1
uint8_t is_sfp[9]; // 0 for non-SFP ports 1 or 2 for the I2C port number
diff --git a/phy.h b/phy.h
index f359fac..795274d 100644
--- a/phy.h
+++ b/phy.h
@@ -22,16 +22,21 @@
#define PHY_ANEG_CTRL 0x00
#define PHY_ANEG_ADV 0x10
#define PHY_ANEG_LP_ABILITY 0x13
-#define PHY_ANEG_MGBASE_CTRL 0x20
-#define PHY_ANEG_MGBASE_ADV 0x21
+#define PHY_ANEG_MGBASE_CTRL 0x20
+#define PHY_ANEG_MGBASE_ADV 0x21
#define PHY_EEE_ADV 0x3c
#define PHY_EEE_LP_ABILITY 0x3d
#define PHY_EEE_ADV2 0x3e
#define PHY_EEE_LP_ABILITY2 0x3f
+
// Register bits for EEE capabilities at a given speed
+// PHY_EEE_ADV2
#define PHY_EEE_BIT_2G5 0x01
+#define PHY_EEE_BIT_5G 0x02
+// PHY_EEE_ADV
#define PHY_EEE_BIT_1G 0x04
#define PHY_EEE_BIT_100M 0x02
+#define PHY_EEE_BIT_10G 0x08
/*
* MMD 31 Registers
diff --git a/rtl837x_init.c b/rtl837x_init.c
index 6fd1c5e..50d94f6 100644
--- a/rtl837x_init.c
+++ b/rtl837x_init.c
@@ -19,14 +19,6 @@ extern __xdata struct machine_runtime machine_detected;
*/
void static sds_init(void)
{
-/*
- p001e.000d:9535 R02f8-00009535 R02f4-0000953a P000001.1e00000d:953a
- p001e.000d:953a p001e.000d:953a R02f8-0000953a R02f4-00009530 P000001.1e00000d:9530
-
- RTL8373:
- p001e.000d:0010 R02f8-00000010 R02f4-0000001a P000001.1e00000d:b7fe
- p001e.000d:0010 p001e.000d:0010 R02f8-00000010 R02f4-00000010 P000001.1e00000d:b7fe
-*/
phy_read(0, PHY_MMD30, 0xd);
uint16_t pval = SFR_DATA_U16;
@@ -55,6 +47,8 @@ void static sds_init(void)
uint16_t pval;
print_string(" N-settings");
+ if (machine.n_10g)
+ print_string(" - 10g");
// Serdes 0 RX PN swap for 64B/66B
sds_read(1, 6, 2);
pval = SFR_DATA_U16;
@@ -70,19 +64,30 @@ void static sds_init(void)
pval = SFR_DATA_U16;
sds_write_v(0, 6, 2, pval | 0x2000);
- if (machine_detected.isRTL8373) {
- // RTL8224: Serdes 0 RX PN swap for 64B/66B
- // We assume that RTL8373N always paired with RTL8224N.
- // This sds register value is 0x0000 at reset.
- // So only write to it.
- RTL8224_SDS_WRITE(0, 6, 2, 0x2000);
- } else {
- // Serdes 0 RX PN swap for 8B/10B
- sds_read(0, 0, 0);
- pval = SFR_DATA_U16;
- sds_write_v(0, 0, 0, pval | 0x200);
+ if (!machine.n_10g) {
+ if (machine_detected.isRTL8373) {
+ // RTL8224: Serdes 0 RX PN swap for 64B/66B
+ // We assume that RTL8373N always paired with RTL8224N.
+ // This sds register value is 0x0000 at reset.
+ // So only write to it.
+ RTL8224_SDS_WRITE(0, 6, 2, 0x2000);
+ } else {
+ // Serdes 0 RX PN swap for 8B/10B
+ sds_read(0, 0, 0);
+ pval = SFR_DATA_U16;
+ sds_write_v(0, 0, 0, pval | 0x200);
+ }
+ } else if (machine.n_10g == 1) {
+ reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE);
+ sfr_mask_data(0, 0x0f,0x0c);
+ reg_write_m(RTL837X_CFG_PHY_MDI_REVERSE);
+ REG_SET(RTL837X_CFG_PHY_TX_POLARITY_SWAP, 0x0000596a);
+ } else if (machine.n_10g == 2) {
+ REG_SET(RTL837X_CFG_PHY_MDI_REVERSE, 0xc);
+ REG_SET(RTL837X_CFG_PHY_TX_POLARITY_SWAP, 0x0000596a);
}
}
+ print_string("\nsds_init done\n");
}
@@ -109,7 +114,7 @@ void rtl8373_init(void) __banked
phy_config_8224();
sds_config_mac(1, SDS_OFF); // Off for now until SFP+ port used
sds_config_mac(2, SDS_SGMII); // For RTL8224
- sds_config(0, SDS_QXGMII);
+ sds_config(0, SDS_QXGMII); // For RTL8224
// SDS 1 setup
// q012100:4902 Q012100:4906 q013605:0000 Q013605:4000 Q011f02:001f q011f15:0086
@@ -163,7 +168,7 @@ void rtl8373_init(void) __banked
reg_bit_set(RTL837X_REG_HW_CONF, 0);
- // enable EEE for all ports at 2.5G and 10G, but don't reset the PHYs
+ // enable EEE for all ports at 2.5G, but don't reset the PHYs
port_eee_enable_all(EEE_2G5 | EEE_NORESET);
// TODO: patch the PHYs
@@ -188,14 +193,26 @@ void rtl8372_init(void) __banked
print_string("\nrtl8372_init called\n");
sds_init();
- phy_config(8); // PHY configuration: External 8221B?
- phy_config(3); // PHY configuration: all internal PHYs?
+ if (machine.n_10g != 2)
+ phy_config(8); // PHY configuration: External 8221B?
+ if (machine.n_10g)
+ phy_config_8261(3, 0);
+ if (machine.n_10g == 2)
+ phy_config_8261(8, 1);
+ else
+ phy_config(3); // PHY configuration: all internal PHYs?
// Set the MAC SerDes Modes Bits 0-4: SDS 0 = 0x2 (0x2), Bits 5-9: SDS 1: 1f (off)
// r7b20:00000bff R7b20-00000bff r7b20:00000bff R7b20-00000bff r7b20:00000bff R7b20-000003ff r7b20:000003ff R7b20-000003e2 r7b20:000003e2 R7b20-000003e2
- reg_read_m(RTL837X_REG_SDS_MODES);
- sfr_mask_data(1, 0, 0x03);
- sfr_mask_data(0, 0, 0xe2);
- reg_write_m(RTL837X_REG_SDS_MODES);
+ if (machine.n_10g == 1) {
+ REG_SET(RTL837X_REG_SDS_MODES, 0x3ed); // Disable SFP for now, set RTL8261BE SDS 0 to 0xd
+ } else if(machine.n_10g == 2) {
+ REG_SET(RTL837X_REG_SDS_MODES, 0x1ad); // Both 10g ports use SDS_QXGMII
+ } else {
+ reg_read_m(RTL837X_REG_SDS_MODES);
+ sfr_mask_data(1, 0, 0x03);
+ sfr_mask_data(0, 0, 0xe2);
+ reg_write_m(RTL837X_REG_SDS_MODES);
+ }
// r0a90:000000f3 R0a90-000000fc
reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE);
@@ -229,7 +246,7 @@ void rtl8372_init(void) __banked
// enable EEE for all ports at 2.5G and 10G, but don't reset the PHYs
- port_eee_enable_all(EEE_2G5 | EEE_NORESET);
+ port_eee_enable_all(EEE_10G | EEE_NORESET);
// TODO: patch the PHYs
diff --git a/rtl837x_leds.c b/rtl837x_leds.c
index e344cd4..86039d2 100644
--- a/rtl837x_leds.c
+++ b/rtl837x_leds.c
@@ -35,6 +35,7 @@ void leds_dump(void) __banked
print_string("RTL837X_REG_LED1_0_SET2: "); print_reg(RTL837X_REG_LED1_0_SET2); write_char('\n');
print_string("RTL837X_REG_LED3_2_SET2: "); print_reg(RTL837X_REG_LED3_2_SET2); write_char('\n');
print_string("RTL837X_REG_LED1_0_SET3: "); print_reg(RTL837X_REG_LED1_0_SET3); write_char('\n');
+ print_string("RTL837X_REG_LED3_2_SET3: "); print_reg(RTL837X_REG_LED3_2_SET3); write_char('\n');
print_string("RTL837X_REG_LED3_0_SET1: "); print_reg(RTL837X_REG_LED3_0_SET1); write_char('\n');
print_string("RTL837X_REG_LED3_0_SET3: "); print_reg(RTL837X_REG_LED3_0_SET3); write_char('\n');
print_string("RTL837X_LED_PORT_SET_SEL: "); print_reg(RTL837X_LED_PORT_SET_SEL); write_char('\n');
diff --git a/rtl837x_phy.c b/rtl837x_phy.c
index 994551c..16fd214 100644
--- a/rtl837x_phy.c
+++ b/rtl837x_phy.c
@@ -86,6 +86,76 @@ void rtl8224_phy_enable(void) __banked
}
+void phy_config_8261(uint8_t phy, uint8_t sds) __banked
+{
+ print_string("phy_config_8261: phy "); print_byte(phy);
+ print_string(" sds "); print_byte(sds); write_char('\n');
+ phy_write(phy, PHY_MMD30, 0x141, 0x80aa); // P000008.1e000141:80aa P000008.1e000143:8c07 p031e.0143:0c07
+ phy_write(phy, PHY_MMD30, 0x143, 0x8c07);
+ phy_read(phy, PHY_MMD30, 0x143);
+ print_phy_data();
+ phy_write(phy, PHY_MMD30, 0x141, 0x5078); // P000008.1e000141:5078 P000008.1e000143:8c86 p031e.0143:0c86
+ phy_write(phy, PHY_MMD30, 0x143, 0x8c86);
+ phy_read(phy, PHY_MMD30, 0x143);
+ print_phy_data();
+ phy_read(phy, PHY_MMD30, 0x105);
+ print_phy_data(); // p031e.0105:0000
+
+ phy_write(phy, PHY_MMD30, 0xe1, 0x00); // P000008.1e0000e1:0000
+ phy_write(phy, PHY_MMD30, 0xe3, 0x00); // P000008.1e0000e3:0000
+ phy_write(phy, PHY_MMD30, 0xe4, 0x01); // P000008.1e0000e4:0001
+ phy_write(phy, PHY_MMD30, 0xe0, 0x2f); // P000008.1e0000e0:002f
+
+ // The following are actually bit-ops:
+ phy_write(phy, PHY_MMD31, 0xa442, 0x8418); // p031f.a442:0418 P000008.1f00a442:8418
+ phy_write(phy, PHY_MMD31, 0xa448, 0x07a0); // p031f.a448:07a0 P000008.1f00a448:07a0
+ phy_write(phy, PHY_MMD31, 0xa43a, 0x003f); // p031f.a43a:0030 P000008.1e0000e2:003f
+
+ phy_write(phy, PHY_MMD31, 0xc800, 0x5a02); // P000008.1f00c800:5a02
+
+ phy_write(phy, PHY_MMD30, 0x01ee, 0x5a02); // p031e.01ee:5a00 P000008.1e0001ee:5a02
+ phy_write(phy, PHY_MMD30, 0x0230, 0x0002); // p031e.0230:0000 P000008.1e000230:0002
+ phy_write(phy, PHY_MMD31, 0xc802, 0x0073); // p031f.c802:0000 P000008.1f00c802:0073
+ phy_write(phy, PHY_MMD30, 0x01ef, 0xe004); // p031e.01ef:0004 P000008.1e0001ef:e004
+ delay(20);
+ phy_write(phy, PHY_MMD30, 0x01ef, 0x0004); // p031e.01ef:e004 P000008.1e0001ef:0004
+ delay(20);
+ phy_write(phy, PHY_MMD30, 0x0230, 0x01c2); // p031e.0230:01c2 P000008.1e000230:0002
+
+ phy_read(phy, PHY_MMD30, 0x103);
+ print_phy_data(); // p031e.0103:8261
+
+ phy_write(phy, PHY_MMD30, 0x01c8, 0x0104); // p031e.01c8:0104 P000008.1e0001c8:0104
+ phy_write(phy, PHY_MMD30, 0x01c9, 0x8080); // p031e.01c9:8080 P000008.1e0001c9:8080
+ phy_write(phy, PHY_MMD30, 0x01ca, 0x2020); // p031e.01ca:2020 P000008.1e0001ca:2020
+ phy_write(phy, PHY_MMD30, 0x0105, 0x0000); // p031e.0105:0000 P000008.1e000105:0000
+ phy_write(phy, PHY_MMD30, 0x00c2, 0x880d); // p031e.00c2:880d P000008.1e0000c2:880d
+ phy_write(phy, PHY_MMD30, 0x03f1, 0x0072); // p031e.03f1:0072 P000008.1e0003f1:0072
+ phy_write(phy, PHY_MMD30, 0x02a2, 0x0010); // p031e.02a2:0010 P000008.1e0002a2:0010
+ phy_write(phy, PHY_MMD30, 0x00c1, 0x0127); // p031e.00c1:0127 P000008.1e0000c1:0127
+ phy_write(phy, PHY_MMD30, 0x00c1, 0x0167); // p031e.00c1:0127 P000008.1e0000c1:0167
+
+ sds_write_v(sds, 0x21, 0x00, 0x4096); // Q002100:4906
+ sds_write_v(sds, 0x36, 0x05, 0x4000); // Q003605:4000
+ sds_write_v(sds, 0x1f, 0x02, 0x001f); // Q001f02:001f
+
+ phy_read(phy, 0x01, 0x0000);
+ print_phy_data(); // p0301.0000:2040
+
+ phy_write(phy, 0x01, 0x0000, 0x2040); // P000008.01000000:2040
+ delay(20);
+
+ sds_write_v(sds, 0, 0, 0x1603); // Q000000:1603
+ delay(20);
+ sds_write_v(sds, 0, 0, 0x1601); // Q000000:1601
+ delay(20);
+ sds_write_v(sds, 0, 0, 0x1603); //Q000000:1603
+ delay(20);
+ // r6330:00005555 R6330-00005555 r7b20:000003ed R7b20-000003ed
+ print_string("\r\nphy_config_8261 done\n");
+}
+
+
void phy_config(uint8_t phy) __banked
{
print_string("\r\nphy_config: ");
@@ -193,6 +263,10 @@ void phy_set_speed(void) __banked
uint16_t v;
print_string("Setting port "); write_char(machine.log_to_phys_port[phy_settings.port] + '0');
+ if (machine.n_10g && phy_settings.port == 3)
+ phy_settings.is10g_port = 1;
+ if (machine.n_10g == 2 && phy_settings.port == 8)
+ phy_settings.is10g_port = 1;
if (phy_settings.speed == PHY_OFF) {
print_string(" to disabled");
} else {
@@ -200,6 +274,8 @@ void phy_set_speed(void) __banked
switch(phy_settings.speed) {
case PHY_SPEED_AUTO:
print_string("auto");
+ if (phy_settings.is10g_port)
+ print_string (" (10g)");
break;
case PHY_SPEED_10M:
print_string("10M");
@@ -246,7 +322,10 @@ void phy_set_speed(void) __banked
// bit 14: SLAVE, bit 13: Multi-Port device, bit 8: 2.5GBit available, 1: LD
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6081);
// GBCR (1000Base-T Control Register, MMD 31.0xA412)
- phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0000, 0x0200); // Loop timing enabled
+ if (phy_settings.is10g_port)
+ phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0000, 0x0e00);
+ else
+ phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0000, 0x0200);
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_CTRL, 0x3200); // Restart AN
} else {
// AN Control Register (MMD 7.0x0000)
@@ -285,6 +364,12 @@ void phy_set_speed(void) __banked
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6081);
// GBCR (1000Base-T Control Register, MMD 31.0xA412)
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0200, 0x0000);
+ } else if (phy_settings.speed == PHY_SPEED_5G) {
+ phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6081);
+ phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0400, 0x0000);
+ } else if (phy_settings.speed == PHY_SPEED_10G) {
+ phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_MGBASE_CTRL, 0x6081);
+ phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0800, 0x0000);
}
}
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_CTRL, 0x3000); // Enable AN
@@ -442,6 +527,10 @@ void phy_show(uint8_t port) __banked
v = SFR_DATA_U16;
if (v & 0x0080)
print_string(" 2500BaseN-Full");
+ if (v & 0x0100)
+ print_string(" 5000BaseN-Full");
+ if (v & 0x1000)
+ print_string(" 10GBaseN-Full");
}
phy_read(port, PHY_MMD_AN, PHY_ANEG_LP_ABILITY);
v = SFR_DATA_U16;
diff --git a/rtl837x_phy.h b/rtl837x_phy.h
index 84ab214..932516a 100644
--- a/rtl837x_phy.h
+++ b/rtl837x_phy.h
@@ -14,6 +14,7 @@ struct phy_settings {
uint8_t duplex;
uint8_t port;
uint8_t speed;
+ uint8_t is10g_port;
};
extern __xdata struct phy_settings phy_settings;
@@ -28,6 +29,7 @@ void phy_reset(uint8_t port) __banked;
void rtl8224_read_reg_u16(uint16_t reg) __banked;
void rtl8224_write_reg_u16(uint16_t reg, uint16_t val) __banked;
void rtl8224_sds_write(uint16_t sds_cmd, uint16_t val) __banked;
+void phy_config_8261(uint8_t phy, uint8_t sds) __banked;
#define RTL8224_SDS_WRITE(sds_id, page, reg, v) uint16_t _sdscmd = (uint16_t)(sds_id & 0x01) | (1 << 14) | (1 << 15); \
_sdscmd |= (page & 0x3F) << 1; \
diff --git a/rtl837x_port.c b/rtl837x_port.c
index ba22a0e..7c48f90 100644
--- a/rtl837x_port.c
+++ b/rtl837x_port.c
@@ -440,6 +440,9 @@ void port_stats_print(void) __banked
case 5:
print_string("2.5G\t");
break;
+ case 6:
+ print_string("5G\t");
+ break;
case 99:
print_string("Down\t");
break;
@@ -489,20 +492,19 @@ void port_eee_enable(__xdata uint8_t port,__xdata uint8_t speed) __banked
return;
}
+ REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), EEE_RX_ENABLE | EEE_TX_ENABLE);
print_string("EEE on for "); print_byte(port); print_string(" speed ");
// Enable all speeds up to the specified speed
- if ((speed & (EEE_100 | EEE_1000 | EEE_2G5)) == EEE_100) {
+ if (speed & EEE_100) {
print_string("100m\n");
- REG_SET(RTL8373_EEE_CTRL_BASE + (port << 2), EEE_100);
// Enable EEE advertisement for 100BASE-T via EEE Advertisement Reg
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, PHY_EEE_BIT_100M);
if (!(speed & EEE_NORESET))
phy_reset(port);
return;
}
- if ((speed & (EEE_100 | EEE_1000 | EEE_2G5)) == EEE_1000) {
+ if (speed & EEE_1000) {
print_string("1g\n");
- REG_SET(RTL8373_EEE_CTRL_BASE + (port << 2), EEE_100 | EEE_1000);
// Disable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV2, 0);
// Enable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
@@ -511,9 +513,8 @@ void port_eee_enable(__xdata uint8_t port,__xdata uint8_t speed) __banked
phy_reset(port);
return;
}
- if ((speed & (EEE_100 | EEE_1000 | EEE_2G5)) == EEE_2G5) {
+ if (speed & EEE_2G5) {
print_string("2g5\n");
- REG_SET(RTL8373_EEE_CTRL_BASE + (port << 2), EEE_100 | EEE_1000 | EEE_2G5);
// Enable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, PHY_EEE_BIT_1G | PHY_EEE_BIT_100M);
// Enable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
@@ -522,6 +523,26 @@ void port_eee_enable(__xdata uint8_t port,__xdata uint8_t speed) __banked
phy_reset(port);
return;
}
+ if (speed & EEE_5G) {
+ print_string("5g\n");
+ // Enable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
+ phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, PHY_EEE_BIT_1G | PHY_EEE_BIT_100M);
+ // Enable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
+ phy_write(port, PHY_MMD_AN, PHY_EEE_ADV2, PHY_EEE_BIT_2G5 | PHY_EEE_BIT_5G);
+ if (!(speed & EEE_NORESET))
+ phy_reset(port);
+ return;
+ }
+ if (speed & EEE_10G) {
+ print_string("10g\n");
+ // Enable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
+ phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, PHY_EEE_BIT_10G | PHY_EEE_BIT_1G | PHY_EEE_BIT_100M);
+ // Enable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
+ phy_write(port, PHY_MMD_AN, PHY_EEE_ADV2, PHY_EEE_BIT_2G5 | PHY_EEE_BIT_5G);
+ if (!(speed & EEE_NORESET))
+ phy_reset(port);
+ return;
+ }
}
@@ -532,7 +553,7 @@ void port_eee_disable(uint8_t port) __banked
return;
print_string("EEE off for "); print_byte(port); write_char('\n');
- REG_SET(RTL8373_EEE_CTRL_BASE + (port << 2), 0);
+ REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), 0);
// Disable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, 0);
// Disable EEE advertisement for 2.5GBASE-T via EEE Advertisement Reg 2
@@ -552,8 +573,24 @@ void port_eee_status(uint8_t port) __banked
uint16_t v;
print_string("Advertising: ");
+
+ if (machine.n_10g) {
+ phy_read(port, PHY_MMD_AN, PHY_EEE_ADV);
+ v = SFR_DATA_U16;
+ if (v & PHY_EEE_BIT_10G)
+ print_string(" 10G");
+ else
+ print_string(" ");
+ }
phy_read(port, PHY_MMD_AN, PHY_EEE_ADV2);
v = SFR_DATA_U16;
+ if (machine.n_10g) {
+ if (v & PHY_EEE_BIT_5G)
+ print_string(" 5G");
+ else
+ print_string(" ");
+ }
+ v = SFR_DATA_U16;
if (v & PHY_EEE_BIT_2G5)
print_string(" 2.5G");
else
@@ -570,8 +607,22 @@ void port_eee_status(uint8_t port) __banked
print_string(" ");
print_string(" Link Partner: ");
+ if (machine.n_10g) {
+ phy_read(port, PHY_MMD_AN, PHY_EEE_LP_ABILITY);
+ v = SFR_DATA_U16;
+ if (v & PHY_EEE_BIT_10G)
+ print_string(" 10G");
+ else
+ print_string(" ");
+ }
phy_read(port, PHY_MMD_AN, PHY_EEE_LP_ABILITY2);
v = SFR_DATA_U16;
+ if (machine.n_10g) {
+ if (v & PHY_EEE_BIT_5G)
+ print_string(" 5G");
+ else
+ print_string(" ");
+ }
if (v & PHY_EEE_BIT_2G5)
print_string(" 2.5G");
else
@@ -599,7 +650,16 @@ void port_eee_status(uint8_t port) __banked
void port_eee_enable_all(__xdata uint8_t speed) __banked
{
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
- port_eee_enable(i, speed);
+ if (i == 3 && machine.n_10g) {
+ port_eee_enable(i, speed);
+ } else if (i == 8 && machine.n_10g == 2) {
+ port_eee_enable(i, speed);
+ } else {
+ if (speed & EEE_10G)
+ port_eee_enable(i, speed & EEE_NORESET | EEE_2G5);
+ else
+ port_eee_enable(i, speed);
+ }
}
}
diff --git a/rtl837x_port.h b/rtl837x_port.h
index 9be1680..ff036b9 100644
--- a/rtl837x_port.h
+++ b/rtl837x_port.h
@@ -33,6 +33,16 @@ struct vlan_settings {
uint16_t tagged;
};
+/*
+ * Port EEE settings
+ */
+#define EEE_100 0x01
+#define EEE_1000 0x04
+#define EEE_2G5 0x10
+#define EEE_5G 0x20
+#define EEE_10G 0x40
+#define EEE_NORESET 0x80
+
extern __xdata struct vlan_settings vlan_settings;
uint8_t port_l2_forget(void) __banked;
diff --git a/rtl837x_regs.h b/rtl837x_regs.h
index c2bfe43..c1a27bb 100644
--- a/rtl837x_regs.h
+++ b/rtl837x_regs.h
@@ -32,6 +32,7 @@
#define RTL837X_REG_LED_GLB_IO_EN 0x65DC
#define RTL837X_REG_LED3_0_SET3 0x6524
#define RTL837X_REG_LED3_0_SET1 0x6528
+#define RTL837X_REG_LED3_2_SET3 0x652C
#define RTL837X_REG_LED1_0_SET3 0x6530
#define RTL837X_REG_LED3_2_SET2 0x6534
#define RTL837X_REG_LED1_0_SET2 0x6538
@@ -268,14 +269,11 @@
/*
* EEE
*/
-#define RTL837X_EEE_STATUS 0x125C
+#define RTL837X_EEE_CTRL_BASE 0x125C
+#define EEE_RX_ENABLE 0x01
+#define EEE_TX_ENABLE 0x02
#define RTL837X_MAC_EEE_ABLTY 0x6404
#define RTL8373_PHY_EEE_ABLTY 0x642C
-#define RTL8373_EEE_CTRL_BASE 0x606c
-#define EEE_100 0x01
-#define EEE_1000 0x04
-#define EEE_2G5 0x10
-#define EEE_NORESET 0x80
/*
* RANDOM
diff --git a/rtlplayground.c b/rtlplayground.c
index 81cbc6e..c2eb5d6 100644
--- a/rtlplayground.c
+++ b/rtlplayground.c
@@ -890,13 +890,14 @@ void early_boot_handle_button(void)
* to connect to an SFP module or a PHY
* Valid modes are SDS_10GR, SDS_QXGMII, SDS_HISGMII, SDS_HSG, SDS_SGMII and SDS_1000BX_FIBER
* The SerDes ID may be 0 or 1 for RTL8272 and 0-2 for RTL8373
+ * SDS_QXGMII is used for 10G Fiber, RTL8224 and RTL8261BE
*/
void sds_config(uint8_t sds, uint8_t mode)
{
print_string("sds_config sds: "); print_byte(sds); print_string(", mode: "); print_byte(mode); write_char('\n');
sds_config_mac(sds, mode);
- if (mode == SDS_10GR || mode == SDS_QXGMII) // 10G Fiber, 10G connection to RTL8224
+ if (mode == SDS_10GR || mode == SDS_QXGMII)
sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480
else
sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480
@@ -932,7 +933,7 @@ void sds_config(uint8_t sds, uint8_t mode)
}
sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200
- if (page == 0x2e) { // 10G Fiber
+ if (page == 0x2e) { // 10G Fiber / SDS_QXGMII
sds_write_v(sds, page, 0x04, 0x0080); // Q012e04:0080
sds_write_v(sds, page, 0x06, 0x0408); // Q012e06:0408
sds_write_v(sds, page, 0x07, 0x020d); // Q012e07:020d
@@ -961,6 +962,30 @@ void sds_config(uint8_t sds, uint8_t mode)
sds_write_v(sds, 0x07, 0x0c, 0x9401); // Q00070c:9401
sds_write_v(sds, 0x1f, 0x0b, 0x0003); // Q001f0b:0003
sds_write_v(sds, 0x06, 0x03, 0xc45c); // Q000603:c45c
+
+ // RTL8261BE
+ if (machine.n_10g && mode == SDS_QXGMII) {
+ sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
+ sds_write_v(sds, 0x07, 0x11, 0x054f); // Q000711:054f
+ sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
+ sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
+ sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
+ sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
+ sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
+ sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
+ sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
+ sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
+ sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
+ sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
+ sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
+ sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
+ sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
+ sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
+ sds_write_v(sds, 0x20, 0x00, 0x0000); // Q002000:0000
+ sds_write_v(sds, 0x1f, 0x00, 0x000b); // Q001f00:000b
+ sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000
+ return;
+ }
if (mode != SDS_QXGMII)
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
@@ -1365,13 +1390,17 @@ void idle(void)
uint8_t p5 = sfr_data[2] >> 4;
uint8_t p5_last = linkbits_last[2] >> 4;
cpy_4(linkbits_last, sfr_data);
- // Handle link change of the RTL8221 PHY, adjust SDS mode
- if (p5_last != p5) {
+ // Handle link change of the RTL8221 PHY, adjust SDS mode, RTL8261BE always uses SDS_QXGMII
+ if (!machine.n_10g && p5_last != p5) {
if (p5 == 0x5) // 2.5GBit Mode
sds_config(0, SDS_HISGMII);
else if (p5 == 0x2) // 1GBit
sds_config(0, SDS_SGMII);
}
+ if (machine.n_10g)
+ sds_config(0, SDS_QXGMII);
+ if (machine.n_10g == 2)
+ sds_config(1, SDS_QXGMII);
} else {
cpy_4(linkbits_last, sfr_data);
}
@@ -1660,7 +1689,11 @@ void init_smi(void)
/* Set the SMI(i.e.I2C) type for PHY polling, 0b01 is 2.5/10G PHY. Disable (0b00) for the SFP-ports
* which are at port 8 and additionally at port 3 for a dual SFP device
*/
- REG_SET(RTL837X_REG_SMI_MAC_TYPE, machine.n_sfp == 2 ? 0x00005515 : 0x00005555);
+ if (machine.n_10g == 2) {
+ REG_SET(RTL837X_REG_SMI_MAC_TYPE, 0x00015555);
+ } else {
+ REG_SET(RTL837X_REG_SMI_MAC_TYPE, machine.n_sfp == 2 ? 0x00005515 : 0x00005555);
+ }
// Configure polling of all PHYs by the MAC to detect link-state changes
if (machine_detected.isRTL8373) {
@@ -1687,6 +1720,11 @@ void init_smi(void)
sfr_mask_data(1, 0x80, 0);
reg_write_m(RTL837X_REG_SMI_PORT0_5_ADDR);
}
+
+ if (machine.n_10g == 2) {
+ // Set address of second external PHY on port 8
+ REG_SET(RTL837X_REG_SMI_PORT6_9_ADDR, 0x000040e6);
+ }
}
@@ -2041,7 +2079,6 @@ void main(void)
setup_i2c();
setup_sfp_gpio();
-
print_string(greeting);
print_string("\nClock register: ");