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