From 7fa26e0ae3635758afda577089e980c3e9b2c6cd Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Tue, 8 Sep 2026 16:37:28 +0200 Subject: [PATCH 1/3] Move the boot and SerDes setup out of the common area into BANK3 The common segment is the scarce one: sixteen kilobytes shared by every bank, and before this it had about 2.5 kB left. Most of what moves here runs once at startup and does not have to sit in it. The two SerDes helpers are the exception: the link-change handler and the SFP polling both reach sds_config() while the switch is running, so they are not startup-only. None of it is reached from an interrupt. boot.c takes setup_i2c, init_smi, nic_setup, rtl8373_revision, rtl8224_enable, early_boot_handle_button, set_hostname_default and the two SerDes helpers. BANK3 is enabled with the linker flag; nothing else in the build needed changing. Everything moved is declared __banked, since every caller is outside BANK3: main() and friends run from the common area and rtl837x_init.c calls sds_config() and sds_config_mac() from BANK2. The calls the moved code makes outward were already banked, so that side needed no work. Common segment 13393 -> 10137 bytes, leaving 5787 free rather than 2531. BANK3 holds 3732. All 34 machines in machine.h build and link. Walking the generated assembly for plain lcalls that cross a bank boundary finds none among 2808 calls; those build cleanly and only fail at run time, so it seemed worth checking by machine rather than by eye. --- Makefile | 3 +- boot.c | 480 +++++++++++++++++++++++++++++++++++++++++++++++ boot.h | 14 ++ rtl837x_common.h | 2 - rtl837x_init.c | 1 + rtlplayground.c | 440 +------------------------------------------ 6 files changed, 498 insertions(+), 442 deletions(-) create mode 100644 boot.c create mode 100644 boot.h diff --git a/Makefile b/Makefile index 6f369d78..b577196b 100644 --- a/Makefile +++ b/Makefile @@ -59,6 +59,7 @@ SRCS = \ dhcp.c \ html_data.c \ rtlplayground.c \ + boot.c \ syslog.c \ udp_apps.c @@ -132,7 +133,7 @@ $(BUILDDIR)/%.rel: %.asm | create_build_dir # mv -f $(addprefix $(basename $^), .lst .rel .sym) . $(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel - $(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^ + $(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-bBANK3=0x34000 -Wl-r -o $@ $^ $(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx objcopy --input-target=ihex -O binary $< $@ diff --git a/boot.c b/boot.c new file mode 100644 index 00000000..c72e24ed --- /dev/null +++ b/boot.c @@ -0,0 +1,480 @@ +#pragma codeseg BANK3 +#pragma constseg BANK3 + +#include <8051.h> +#include +#include + +#include "rtl837x_sfr.h" +#include "rtl837x_regs.h" +#include "rtl837x_common.h" +#include "rtl837x_flash.h" +#include "rtl837x_pins.h" +#include "rtl837x_phy.h" +#include "rtl837x_port.h" +#include "rtl837x_init.h" +#include "machine.h" +#include "phy.h" +#include "boot.h" + +extern __code const struct machine machine; +extern __xdata struct machine_runtime machine_detected; +extern __xdata uint8_t sfr_data[4]; +extern volatile __xdata uint32_t ticks; +extern __xdata uint8_t tx_seq; +extern __code uint8_t * __code hex; + + + +void sds_config_mac(uint8_t sds, uint8_t mode) __banked +{ + reg_read_m(RTL837X_REG_SDS_MODES); + sfr_data[0] = 0; + sfr_data[1] = 0; + switch (sds) { + case 0: + sfr_mask_data(0, 0x1f, mode); + break; + case 1: + sfr_mask_data(0, 0xe0, mode << 5); + sfr_mask_data(1, 0x03, mode >> 3); + break; + case 2: + sfr_mask_data(1, 0xfc, 0x02 << 2); + } + if (machine_detected.isRTL8373) // Set 3rd SERDES Mode to 0x2 for RTL8224 + sfr_mask_data(1, 0xfc, 0x02 << 2); + else + sfr_data[2] &= 0x03; + reg_write_m(RTL837X_REG_SDS_MODES); + print_string("\nRTL837X_REG_SDS_MODES: "); + print_reg(RTL837X_REG_SDS_MODES); + print_string("\n"); +} + + + +void early_boot_handle_button(void) __banked +{ + if (machine.reset_pin == GPIO_NA) + return; + + gpio_input_setup(machine.reset_pin); + + // Debounce after init + delay(100); + // If the button is not already held at boot, continue normally. + if (gpio_pin_test(machine.reset_pin)) + return; + + set_sys_led_state(SYS_LED_FAST); + print_string("\n[Reset button held at boot]\n"); + + if (gpio_pin_test(machine.reset_pin)) + return; + + const __xdata uint32_t min_hold_ticks = 10UL * SYS_TICK_HZ; + const __xdata uint32_t max_hold_ticks = 30UL * SYS_TICK_HZ; + const __xdata uint32_t blink_ticks = SYS_TICK_HZ / 10; // 100 ms + const __xdata uint32_t pause_ticks = SYS_TICK_HZ / 2; // 500 ms + __xdata uint32_t start_ticks = ticks; + __xdata uint32_t last_blink_step = start_ticks; + __xdata uint8_t blink_step = 0; + + set_sys_led_state(SYS_LED_ON); + + while (!gpio_pin_test(machine.reset_pin)) { + __xdata uint32_t held_ticks = ticks - start_ticks; + + if (held_ticks > max_hold_ticks) { + print_string("[Button held >30s at boot; continuing normal boot]\n"); + return; + } + + // Double blink pattern while button is held: + // ON (100ms), OFF (100ms), ON (100ms), OFF (500ms) + __xdata uint32_t step_ticks = (blink_step == 3) ? pause_ticks : blink_ticks; + if ((ticks - last_blink_step) >= step_ticks) { + blink_step = (blink_step + 1) & 0x3; + set_sys_led_state((blink_step == 0 || blink_step == 2) ? SYS_LED_ON : SYS_LED_OFF); + last_blink_step = ticks; + } + + PCON |= 1; + } + + set_sys_led_state(SYS_LED_ON); + + if ((ticks - start_ticks) >= min_hold_ticks) { + print_string("[Button held 10s-30s at boot; restoring default config]\n"); + set_sys_led_state(SYS_LED_FAST); + flash_default_config(); + delay(3UL * SYS_TICK_HZ); + } +} + + +/* + * Configure the SerDes of the SoC for a particular mode + * 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) __banked +{ + 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) + sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480 + else + sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480 + sds_write_v(sds, 0x21, 0x13, 0x0400); // Q002113:0400 + sds_write_v(sds, 0x21, 0x18, 0x6d02); // Q002118:6d02 + sds_write_v(sds, 0x21, 0x1b, 0x424e); // Q00211b:424e + sds_write_v(sds, 0x21, 0x1d, 0x0002); // Q00211d:0002 + sds_write_v(sds, 0x36, 0x1c, 0x1390); // Q00361c:1390 + sds_write_v(sds, 0x36, 0x14, 0x003f); // Q003614:003f + + uint8_t page = 0; + uint16_t v = 0; + + switch (mode) { + case SDS_SGMII: + case SDS_1000BX_FIBER: + v = 0x0300; + page = 0x24; + break; + case SDS_HISGMII: + case SDS_HSG: + v = 0x0200; + page = 0x28; + break; + case SDS_10GR: + case SDS_QXGMII: + v = 0x0200; + page = 0x2e; + break; + case SDS_100FX: + v = 0x0200; + page = 0x26; + break; + default: + print_string("Error in SDS Mode\n"); + return; + } + sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200 + + 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 + sds_write_v(sds, page, 0x09, 0x0601); // Q012e09:0601 + sds_write_v(sds, page, 0x0b, 0x222c); // Q012e0b:222c + sds_write_v(sds, page, 0x0c, 0xa217); // Q012e0c:a217 + sds_write_v(sds, page, 0x0d, 0xfe40); // Q012e0d:fe40 + sds_write_v(sds, page, 0x15, 0xf5c1); // Q012e15:f5c1 + } else { + sds_write_v(sds, page, 0x04, 0x0080); // Q002804:0080 + sds_write_v(sds, page, 0x07, 0x1201); // Q002807:1201 + sds_write_v(sds, page, 0x09, 0x0601); // Q002809:0601 + sds_write_v(sds, page, 0x0b, 0x232c); // Q00280b:232c + sds_write_v(sds, page, 0x0c, 0x9217); // Q00280c:9217 + sds_write_v(sds, page, 0x0f, 0x5b50); // Q00280f:5b50 + sds_write_v(sds, page, 0x15, 0xe7c1); // Q002815:e7f1 BUG ! + } + + sds_write_v(sds, page, 0x16, 0x0443); // Q002816:0443 / Q012e16:0443 + sds_write_v(sds, page, 0x1d, 0xabb0); // Q00281d:abb0 / Q012e1d:abb0 + + sds_write_v(sds, 0x06, 0x12, 0x5078); // Q000612:5078 + sds_write_v(sds, 0x07, 0x06, 0x9401); // Q000706:9401 + sds_write_v(sds, 0x07, 0x08, 0x9401); // Q000708:9401 + sds_write_v(sds, 0x07, 0x0a, 0x9401); // Q00070a:9401 + 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 + + if (mode == SDS_1000BX_FIBER) { + sds_write_v(sds, 0x02, 0x04, 0x0020); // Q000204:0020 + sds_write_v(sds, 0x00, 0x02, 0x73d0); // Q000002:73d0 + sds_write_v(sds, 0x00, 0x04, 0x074d); // Q000004:074d + sds_write_v(sds, 0x20, 0x04, 0x0000); // Q002000:0000 + sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000 + } +} + + + + +void rtl8224_enable(void) __banked +{ + // Set Pin 4 low + reg_bit_clear(RTL837X_REG_GPIO_32_63_OUTPUT, 4); + // Configure Pin as output + reg_bit_set(RTL837X_REG_GPIO_32_63_DIRECTION, 4); + delay(100); + // Set pin 4 high + reg_bit_set(RTL837X_REG_GPIO_32_63_OUTPUT, 4); + delay(500); +} + + + +void nic_setup(void) __banked +{ + // Enable NIC + // r6040:00000100 R6040-00001100 + reg_bit_set(RTL837X_REG_HW_CONF, 0xc); + + // This sets the size of the RX buffer, the filling level is in 0x7874 + // R7848-000004ff + REG_SET(RTL837X_REG_NIC_RXBUFF_RX, 0x4ff); + + // R7844-000007fe + REG_SET(RTL837X_REG_NIC_BUFFSIZE_TX, 0x7fe); + + // Configure NIC RX to receive various types of packets + // RTL837X_REG_RX_CTRL: Set bits 24-31 to 0x4, clear bits 16/17 + reg_read_m(RTL837X_REG_RX_CTRL); + sfr_mask_data(3, 0xff, 0x04); + sfr_mask_data(2, 0x03, 0); + reg_write_m(RTL837X_REG_RX_CTRL); + + // Enable NIC TX (set bit 0) + reg_bit_set(RTL837X_REG_TX_CTRL, 0); + + // Enable NIC RX (set bit 0) + reg_bit_set(RTL837X_REG_RX_CTRL, 0); + + // Drop packets with invalid CRC + reg_bit_clear(RTL837X_REG_RX_CTRL, 2); + + // R603c-00000200 + // CPU-port is CPU-Tag aware (bit 9) + REG_SET(RTL837X_REG_CPU_TAG_AWARE_PMASK, 0x200); + + // Insert CPU-tag for internally received packets (bit 0), MODE is 0, i.e. ALL packets (bits 8-9) + reg_read_m(RTL837X_REG_CPU_TAG); + sfr_mask_data(0, 1, 1); + sfr_mask_data(1, 3, 0); + reg_write_m(RTL837X_REG_CPU_TAG); + + // Force MAC mode of the CPU port (port 9) + // r6368:00000194 R6368-00000197 + reg_read_m(RTL837X_REG_MAC_FORCE_MODE + 9 * 4); + sfr_mask_data(0, 0, 3); // Set bits 0, 1: Force link + reg_write_m(RTL837X_REG_MAC_FORCE_MODE+ 9 * 4); + + // Sequence number of TX packets + tx_seq = 0; +} + + + +void rtl8373_revision(void) __banked +{ + reg_read_m(RTL837X_REG_CHIP_INFO); + sfr_mask_data(2, 0x0a, 0x0a); // Enable reading version + reg_write_m(RTL837X_REG_CHIP_INFO); + delay(50); + + reg_read_m(RTL837X_REG_CHIP_INFO); + print_string("CPU revision: "); print_byte(sfr_data[2]); print_byte(sfr_data[2]); write_char('\n'); + sfr_mask_data(2, 0x0a, 0x00); // Enable reading version + reg_write_m(RTL837X_REG_CHIP_INFO); +} + + +/* + * The SoC manages Link-State for steering the LEDs and can set PHY-settings + * automatically through Realtek's SMI (Simple Managagement) Interface, a + * proprietary version of MDIO which for example allows for more PHYs on the same + * bus. + * Configure polling via SMI and the interface setup during boot. + */ +void init_smi(void) __banked +{ + print_string("\ninit_switch called\n"); + + /* 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 + */ + + // Default: 0x00005555 + // Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x00005555; + SFR_DATA_U16_UPPER = 0x0000; + SFR_DATA_U16 = 0x5555; + if (machine.n_10g == 2) { + // 0x00015555, only change the bytes that differs from the default. + SFR_DATA_16 = 0x01; + } else if (machine.n_sfp == 2) + // 0x00005515 + SFR_DATA_0 = 0x15; + reg_write(RTL837X_REG_SMI_MAC_TYPE); + + // Configure polling of all PHYs by the MAC to detect link-state changes + // Default: 0x000000ff + // Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x000000ff; + SFR_DATA_U16_UPPER = 0x0000; + SFR_DATA_U16 = 0x00ff; + if (!machine_detected.isRTL8373) { + if (machine.n_sfp == 2) { + // 0x000000f0, only change the bytes that differs from the default. + SFR_DATA_0 = 0xf0; + } else { + // 0x000001f8, only change the bytes that differs from the default. + SFR_DATA_8 = 0x01; + SFR_DATA_0 = 0xf8; + } + } + reg_write(RTL837X_REG_SMI_PORT_POLLING); + // Enable MDC + reg_read_m(RTL837X_REG_SMI_CTRL); + sfr_mask_data(1, 0, 0x70); // Set bits 12-14 to enable MDC for SMI0-SMI2 + reg_write_m(RTL837X_REG_SMI_CTRL); + delay(50); + + if (!machine_detected.isRTL8373) { + // Change I2C addresses for SMI of the non-existent PHYs + // r6450:000020e6 R6450-000000e6 + reg_read_m(RTL837X_REG_SMI_PORT6_9_ADDR); + sfr_mask_data(1, 0x7c, 0); + reg_write_m(RTL837X_REG_SMI_PORT6_9_ADDR); + + // r644c:0a418820 R644c-0a400820 + reg_read_m(RTL837X_REG_SMI_PORT0_5_ADDR); + sfr_mask_data(2, 0x0f, 0); + 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); + } +} + + + + +void setup_i2c(void) __banked +{ + REG_SET(RTL837X_REG_I2C_MST_IF_CTRL, 0); + // Configure SFP EEPROM address (0x50) as I2C device address + // Configure SFP readings address (0x51) as I2C device address + REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16), 0x50 >> 5, (0x50 << 3) & 0xff); + + REG_SET(RTL837X_REG_I2C_CTRL2, 0); + + // HW Control register, enable I2C depending on PIN configuration + reg_read_m(RTL837X_PIN_MUX_1); + for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) { + const uint8_t scl_bus = i2c_bus_from_scl_pin(machine.sfp_port[sfp].i2c.scl); + const uint8_t sda_bus = i2c_bus_from_sda_pin(machine.sfp_port[sfp].i2c.sda); + print_string("Configuring I2C for SFP idx="); print_byte(sfp); print_string(" SCL="); print_byte(scl_bus); print_string(", SDA="); print_byte(sda_bus); write_char('\n'); + switch (scl_bus) { + case 3: + // Bit 5-6 0b10 -> SCL (implies enabled SDA on bus 3) + sfr_mask_data(0, 0x60, 0x40); + break; + case 2: + // Bit 15-16 0b01 -> SCL + sfr_mask_data(1, 0x80, 0x80); + sfr_mask_data(2, 0x01, 0x00); + break; + case 1: + // Bit 11-12 0b01 -> SCL + sfr_mask_data(1, 0x18, 0x08); + break; + case 0: + // Bit 7-8 0b01 -> SCL + sfr_mask_data(0, 0x80, 0x80); + sfr_mask_data(1, 0x01, 0x00); + break; + default: + print_string("Invalid SCL bus number: "); print_byte(scl_bus); write_char('\n'); + } + + switch (sda_bus) { + case 4: + // Bit 29 0b0 -> SDA + sfr_mask_data(3, 0x20, 0x00); + break; + case 3: + // Bit 5-6 0b10 -> SDA (implies enabled SCL on bus 3) + sfr_mask_data(0, 0x60, 0x40); + break; + case 2: + // Bit 17-18 0b01 -> SDA + sfr_mask_data(2, 0x06, 0x02); + break; + case 1: + // Bit 13-14 0b01 -> SDA + sfr_mask_data(1, 0x60, 0x20); + break; + case 0: + // Bit 9-10 0b01 -> SDA + sfr_mask_data(1, 0x06, 0x02); + break; + default: + print_string("Invalid SDA bus number: "); print_byte(sda_bus); write_char('\n'); + } + } + reg_write_m(RTL837X_PIN_MUX_1); +} + + +/* Give the switch a name carrying the tail of its MAC, so several of them on + * one network are distinguishable out of the box. Called after the startup + * config has been replayed and returns at once if that config already set a + * name, so a configured switch does no work for it (suggested in review). + * + * Written without a loop on purpose. Locals - counters and pointers alike - + * land in the 8051's internal-RAM overlay, and on an image with LACP and STP + * both enabled that overlay is exhausted: a loop here makes the linker fail + * with "Could not get 8 consecutive bytes in internal RAM for area OSEG". + * Moving the code into its own function does not help; the overlay is shared + * across the whole image. Hoisting the locals to xdata does not help either, + * because itohex() is inline and brings its own frame. */ +void set_hostname_default(void) __banked +{ + if (hostname[0] != NUL) + return; + + strcpy((__xdata uint8_t *)hostname, "RTLPlayground-"); + hostname[14] = hex[uip_ethaddr.addr[3] >> 4]; + hostname[15] = hex[uip_ethaddr.addr[3] & 0xf]; + hostname[16] = hex[uip_ethaddr.addr[4] >> 4]; + hostname[17] = hex[uip_ethaddr.addr[4] & 0xf]; + hostname[18] = hex[uip_ethaddr.addr[5] >> 4]; + hostname[19] = hex[uip_ethaddr.addr[5] & 0xf]; + hostname[20] = NUL; +} diff --git a/boot.h b/boot.h new file mode 100644 index 00000000..18ffe88c --- /dev/null +++ b/boot.h @@ -0,0 +1,14 @@ +#ifndef BOOT_H +#define BOOT_H + +void sds_config_mac(uint8_t sds, uint8_t mode) __banked; +void sds_config(uint8_t sds, uint8_t mode) __banked; +void early_boot_handle_button(void) __banked; +void rtl8224_enable(void) __banked; +void nic_setup(void) __banked; +void rtl8373_revision(void) __banked; +void init_smi(void) __banked; +void setup_i2c(void) __banked; +void set_hostname_default(void) __banked; + +#endif diff --git a/rtl837x_common.h b/rtl837x_common.h index e4b90fed..572b4bfb 100644 --- a/rtl837x_common.h +++ b/rtl837x_common.h @@ -190,7 +190,5 @@ bool gpio_pin_test(uint8_t pin); void set_sys_led_state(uint8_t state); void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg); void sds_write_v(uint8_t sds_id, uint8_t page, uint8_t reg, uint16_t v); -void sds_config_mac(uint8_t sds, uint8_t mode); -void sds_config(uint8_t sds, uint8_t mode); void handle_sfp(void); #endif diff --git a/rtl837x_init.c b/rtl837x_init.c index 50d94f60..6b24843b 100644 --- a/rtl837x_init.c +++ b/rtl837x_init.c @@ -6,6 +6,7 @@ #include "rtl837x_phy.h" #include "phy.h" #include "machine.h" +#include "boot.h" extern __xdata uint8_t sfr_data[4]; extern __code struct machine machine; diff --git a/rtlplayground.c b/rtlplayground.c index 38d9dd9c..d2346804 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -26,6 +26,7 @@ #include "phy.h" #include "syslog.h" #include "httpd/page_impl.h" +#include "boot.h" extern __code const struct machine machine; extern __xdata uint32_t flash_size; @@ -34,7 +35,6 @@ extern __xdata uint16_t crc_value; __xdata struct machine_runtime machine_detected; void crc16_bank1(__xdata uint8_t *v) __naked; void flash_default_config(void); -void early_boot_handle_button(void); // See setup_serial_timer1() for valid baudrate settings! #define SERIAL_BAUD_RATE 115200 @@ -944,33 +944,6 @@ void read_reg_timer(__xdata uint32_t * tmr) } -void sds_config_mac(uint8_t sds, uint8_t mode) -{ - reg_read_m(RTL837X_REG_SDS_MODES); - sfr_data[0] = 0; - sfr_data[1] = 0; - switch (sds) { - case 0: - sfr_mask_data(0, 0x1f, mode); - break; - case 1: - sfr_mask_data(0, 0xe0, mode << 5); - sfr_mask_data(1, 0x03, mode >> 3); - break; - case 2: - sfr_mask_data(1, 0xfc, 0x02 << 2); - } - if (machine_detected.isRTL8373) // Set 3rd SERDES Mode to 0x2 for RTL8224 - sfr_mask_data(1, 0xfc, 0x02 << 2); - else - sfr_data[2] &= 0x03; - reg_write_m(RTL837X_REG_SDS_MODES); - print_string("\nRTL837X_REG_SDS_MODES: "); - print_reg(RTL837X_REG_SDS_MODES); - print_string("\n"); -} - - // Delay for given number of ticks without doing housekeeping void delay(uint16_t t) { @@ -979,181 +952,6 @@ void delay(uint16_t t) PCON |= 1; } -void early_boot_handle_button(void) -{ - if (machine.reset_pin == GPIO_NA) - return; - - gpio_input_setup(machine.reset_pin); - - // Debounce after init - delay(100); - // If the button is not already held at boot, continue normally. - if (gpio_pin_test(machine.reset_pin)) - return; - - set_sys_led_state(SYS_LED_FAST); - print_string("\n[Reset button held at boot]\n"); - - if (gpio_pin_test(machine.reset_pin)) - return; - - const __xdata uint32_t min_hold_ticks = 10UL * SYS_TICK_HZ; - const __xdata uint32_t max_hold_ticks = 30UL * SYS_TICK_HZ; - const __xdata uint32_t blink_ticks = SYS_TICK_HZ / 10; // 100 ms - const __xdata uint32_t pause_ticks = SYS_TICK_HZ / 2; // 500 ms - __xdata uint32_t start_ticks = ticks; - __xdata uint32_t last_blink_step = start_ticks; - __xdata uint8_t blink_step = 0; - - set_sys_led_state(SYS_LED_ON); - - while (!gpio_pin_test(machine.reset_pin)) { - __xdata uint32_t held_ticks = ticks - start_ticks; - - if (held_ticks > max_hold_ticks) { - print_string("[Button held >30s at boot; continuing normal boot]\n"); - return; - } - - // Double blink pattern while button is held: - // ON (100ms), OFF (100ms), ON (100ms), OFF (500ms) - __xdata uint32_t step_ticks = (blink_step == 3) ? pause_ticks : blink_ticks; - if ((ticks - last_blink_step) >= step_ticks) { - blink_step = (blink_step + 1) & 0x3; - set_sys_led_state((blink_step == 0 || blink_step == 2) ? SYS_LED_ON : SYS_LED_OFF); - last_blink_step = ticks; - } - - PCON |= 1; - } - - set_sys_led_state(SYS_LED_ON); - - if ((ticks - start_ticks) >= min_hold_ticks) { - print_string("[Button held 10s-30s at boot; restoring default config]\n"); - set_sys_led_state(SYS_LED_FAST); - flash_default_config(); - delay(3UL * SYS_TICK_HZ); - } -} - -/* - * Configure the SerDes of the SoC for a particular mode - * 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) - sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480 - else - sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480 - sds_write_v(sds, 0x21, 0x13, 0x0400); // Q002113:0400 - sds_write_v(sds, 0x21, 0x18, 0x6d02); // Q002118:6d02 - sds_write_v(sds, 0x21, 0x1b, 0x424e); // Q00211b:424e - sds_write_v(sds, 0x21, 0x1d, 0x0002); // Q00211d:0002 - sds_write_v(sds, 0x36, 0x1c, 0x1390); // Q00361c:1390 - sds_write_v(sds, 0x36, 0x14, 0x003f); // Q003614:003f - - uint8_t page = 0; - uint16_t v = 0; - - switch (mode) { - case SDS_SGMII: - case SDS_1000BX_FIBER: - v = 0x0300; - page = 0x24; - break; - case SDS_HISGMII: - case SDS_HSG: - v = 0x0200; - page = 0x28; - break; - case SDS_10GR: - case SDS_QXGMII: - v = 0x0200; - page = 0x2e; - break; - case SDS_100FX: - v = 0x0200; - page = 0x26; - break; - default: - print_string("Error in SDS Mode\n"); - return; - } - sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200 - - 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 - sds_write_v(sds, page, 0x09, 0x0601); // Q012e09:0601 - sds_write_v(sds, page, 0x0b, 0x222c); // Q012e0b:222c - sds_write_v(sds, page, 0x0c, 0xa217); // Q012e0c:a217 - sds_write_v(sds, page, 0x0d, 0xfe40); // Q012e0d:fe40 - sds_write_v(sds, page, 0x15, 0xf5c1); // Q012e15:f5c1 - } else { - sds_write_v(sds, page, 0x04, 0x0080); // Q002804:0080 - sds_write_v(sds, page, 0x07, 0x1201); // Q002807:1201 - sds_write_v(sds, page, 0x09, 0x0601); // Q002809:0601 - sds_write_v(sds, page, 0x0b, 0x232c); // Q00280b:232c - sds_write_v(sds, page, 0x0c, 0x9217); // Q00280c:9217 - sds_write_v(sds, page, 0x0f, 0x5b50); // Q00280f:5b50 - sds_write_v(sds, page, 0x15, 0xe7c1); // Q002815:e7f1 BUG ! - } - - sds_write_v(sds, page, 0x16, 0x0443); // Q002816:0443 / Q012e16:0443 - sds_write_v(sds, page, 0x1d, 0xabb0); // Q00281d:abb0 / Q012e1d:abb0 - - sds_write_v(sds, 0x06, 0x12, 0x5078); // Q000612:5078 - sds_write_v(sds, 0x07, 0x06, 0x9401); // Q000706:9401 - sds_write_v(sds, 0x07, 0x08, 0x9401); // Q000708:9401 - sds_write_v(sds, 0x07, 0x0a, 0x9401); // Q00070a:9401 - 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 - - if (mode == SDS_1000BX_FIBER) { - sds_write_v(sds, 0x02, 0x04, 0x0020); // Q000204:0020 - sds_write_v(sds, 0x00, 0x02, 0x73d0); // Q000002:73d0 - sds_write_v(sds, 0x00, 0x04, 0x074d); // Q000004:074d - sds_write_v(sds, 0x20, 0x04, 0x0000); // Q002000:0000 - sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000 - } -} /* @@ -1681,19 +1479,6 @@ void setup_external_irqs(void) } -void rtl8224_enable(void) -{ - // Set Pin 4 low - reg_bit_clear(RTL837X_REG_GPIO_32_63_OUTPUT, 4); - // Configure Pin as output - reg_bit_set(RTL837X_REG_GPIO_32_63_DIRECTION, 4); - delay(100); - // Set pin 4 high - reg_bit_set(RTL837X_REG_GPIO_32_63_OUTPUT, 4); - delay(500); -} - - /* * Set dividers for a chosen CPU frequency */ @@ -1816,55 +1601,6 @@ void phy_modify(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t mask, uin } while (SFR_EXEC_STATUS != 0); } -void nic_setup(void) -{ - // Enable NIC - // r6040:00000100 R6040-00001100 - reg_bit_set(RTL837X_REG_HW_CONF, 0xc); - - // This sets the size of the RX buffer, the filling level is in 0x7874 - // R7848-000004ff - REG_SET(RTL837X_REG_NIC_RXBUFF_RX, 0x4ff); - - // R7844-000007fe - REG_SET(RTL837X_REG_NIC_BUFFSIZE_TX, 0x7fe); - - // Configure NIC RX to receive various types of packets - // RTL837X_REG_RX_CTRL: Set bits 24-31 to 0x4, clear bits 16/17 - reg_read_m(RTL837X_REG_RX_CTRL); - sfr_mask_data(3, 0xff, 0x04); - sfr_mask_data(2, 0x03, 0); - reg_write_m(RTL837X_REG_RX_CTRL); - - // Enable NIC TX (set bit 0) - reg_bit_set(RTL837X_REG_TX_CTRL, 0); - - // Enable NIC RX (set bit 0) - reg_bit_set(RTL837X_REG_RX_CTRL, 0); - - // Drop packets with invalid CRC - reg_bit_clear(RTL837X_REG_RX_CTRL, 2); - - // R603c-00000200 - // CPU-port is CPU-Tag aware (bit 9) - REG_SET(RTL837X_REG_CPU_TAG_AWARE_PMASK, 0x200); - - // Insert CPU-tag for internally received packets (bit 0), MODE is 0, i.e. ALL packets (bits 8-9) - reg_read_m(RTL837X_REG_CPU_TAG); - sfr_mask_data(0, 1, 1); - sfr_mask_data(1, 3, 0); - reg_write_m(RTL837X_REG_CPU_TAG); - - // Force MAC mode of the CPU port (port 9) - // r6368:00000194 R6368-00000197 - reg_read_m(RTL837X_REG_MAC_FORCE_MODE + 9 * 4); - sfr_mask_data(0, 0, 3); // Set bits 0, 1: Force link - reg_write_m(RTL837X_REG_MAC_FORCE_MODE+ 9 * 4); - - // Sequence number of TX packets - tx_seq = 0; -} - void set_sys_led_state(uint8_t state) { @@ -1873,88 +1609,7 @@ void set_sys_led_state(uint8_t state) reg_write_m(RTL837X_REG_LED_MODE); } -void rtl8373_revision(void) -{ - reg_read_m(RTL837X_REG_CHIP_INFO); - sfr_mask_data(2, 0x0a, 0x0a); // Enable reading version - reg_write_m(RTL837X_REG_CHIP_INFO); - delay(50); - reg_read_m(RTL837X_REG_CHIP_INFO); - print_string("CPU revision: "); print_byte(sfr_data[2]); print_byte(sfr_data[2]); write_char('\n'); - sfr_mask_data(2, 0x0a, 0x00); // Enable reading version - reg_write_m(RTL837X_REG_CHIP_INFO); -} - - -/* - * The SoC manages Link-State for steering the LEDs and can set PHY-settings - * automatically through Realtek's SMI (Simple Managagement) Interface, a - * proprietary version of MDIO which for example allows for more PHYs on the same - * bus. - * Configure polling via SMI and the interface setup during boot. - */ -void init_smi(void) -{ - print_string("\ninit_switch called\n"); - - /* 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 - */ - - // Default: 0x00005555 - // Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x00005555; - SFR_DATA_U16_UPPER = 0x0000; - SFR_DATA_U16 = 0x5555; - if (machine.n_10g == 2) { - // 0x00015555, only change the bytes that differs from the default. - SFR_DATA_16 = 0x01; - } else if (machine.n_sfp == 2) - // 0x00005515 - SFR_DATA_0 = 0x15; - reg_write(RTL837X_REG_SMI_MAC_TYPE); - - // Configure polling of all PHYs by the MAC to detect link-state changes - // Default: 0x000000ff - // Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x000000ff; - SFR_DATA_U16_UPPER = 0x0000; - SFR_DATA_U16 = 0x00ff; - if (!machine_detected.isRTL8373) { - if (machine.n_sfp == 2) { - // 0x000000f0, only change the bytes that differs from the default. - SFR_DATA_0 = 0xf0; - } else { - // 0x000001f8, only change the bytes that differs from the default. - SFR_DATA_8 = 0x01; - SFR_DATA_0 = 0xf8; - } - } - reg_write(RTL837X_REG_SMI_PORT_POLLING); - // Enable MDC - reg_read_m(RTL837X_REG_SMI_CTRL); - sfr_mask_data(1, 0, 0x70); // Set bits 12-14 to enable MDC for SMI0-SMI2 - reg_write_m(RTL837X_REG_SMI_CTRL); - delay(50); - - if (!machine_detected.isRTL8373) { - // Change I2C addresses for SMI of the non-existent PHYs - // r6450:000020e6 R6450-000000e6 - reg_read_m(RTL837X_REG_SMI_PORT6_9_ADDR); - sfr_mask_data(1, 0x7c, 0); - reg_write_m(RTL837X_REG_SMI_PORT6_9_ADDR); - - // r644c:0a418820 R644c-0a400820 - reg_read_m(RTL837X_REG_SMI_PORT0_5_ADDR); - sfr_mask_data(2, 0x0f, 0); - 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); - } -} /* Set up serial port 0 using Timer 1 as baudrate generator. @@ -2008,73 +1663,6 @@ void setup_serial_timer1(void) } -void setup_i2c(void) -{ - REG_SET(RTL837X_REG_I2C_MST_IF_CTRL, 0); - // Configure SFP EEPROM address (0x50) as I2C device address - // Configure SFP readings address (0x51) as I2C device address - REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16), 0x50 >> 5, (0x50 << 3) & 0xff); - - REG_SET(RTL837X_REG_I2C_CTRL2, 0); - - // HW Control register, enable I2C depending on PIN configuration - reg_read_m(RTL837X_PIN_MUX_1); - for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) { - const uint8_t scl_bus = i2c_bus_from_scl_pin(machine.sfp_port[sfp].i2c.scl); - const uint8_t sda_bus = i2c_bus_from_sda_pin(machine.sfp_port[sfp].i2c.sda); - print_string("Configuring I2C for SFP idx="); print_byte(sfp); print_string(" SCL="); print_byte(scl_bus); print_string(", SDA="); print_byte(sda_bus); write_char('\n'); - switch (scl_bus) { - case 3: - // Bit 5-6 0b10 -> SCL (implies enabled SDA on bus 3) - sfr_mask_data(0, 0x60, 0x40); - break; - case 2: - // Bit 15-16 0b01 -> SCL - sfr_mask_data(1, 0x80, 0x80); - sfr_mask_data(2, 0x01, 0x00); - break; - case 1: - // Bit 11-12 0b01 -> SCL - sfr_mask_data(1, 0x18, 0x08); - break; - case 0: - // Bit 7-8 0b01 -> SCL - sfr_mask_data(0, 0x80, 0x80); - sfr_mask_data(1, 0x01, 0x00); - break; - default: - print_string("Invalid SCL bus number: "); print_byte(scl_bus); write_char('\n'); - } - - switch (sda_bus) { - case 4: - // Bit 29 0b0 -> SDA - sfr_mask_data(3, 0x20, 0x00); - break; - case 3: - // Bit 5-6 0b10 -> SDA (implies enabled SCL on bus 3) - sfr_mask_data(0, 0x60, 0x40); - break; - case 2: - // Bit 17-18 0b01 -> SDA - sfr_mask_data(2, 0x06, 0x02); - break; - case 1: - // Bit 13-14 0b01 -> SDA - sfr_mask_data(1, 0x60, 0x20); - break; - case 0: - // Bit 9-10 0b01 -> SDA - sfr_mask_data(1, 0x06, 0x02); - break; - default: - print_string("Invalid SDA bus number: "); print_byte(sda_bus); write_char('\n'); - } - } - reg_write_m(RTL837X_PIN_MUX_1); -} - - void check_and_flash_update_image(void) { flash_read_jedecid(); // This initializes also __xdata flash_size variable @@ -2160,32 +1748,6 @@ void check_and_flash_update_image(void) } } -/* Give the switch a name carrying the tail of its MAC, so several of them on - * one network are distinguishable out of the box. Called after the startup - * config has been replayed and returns at once if that config already set a - * name, so a configured switch does no work for it (suggested in review). - * - * Written without a loop on purpose. Locals - counters and pointers alike - - * land in the 8051's internal-RAM overlay, and on an image with LACP and STP - * both enabled that overlay is exhausted: a loop here makes the linker fail - * with "Could not get 8 consecutive bytes in internal RAM for area OSEG". - * Moving the code into its own function does not help; the overlay is shared - * across the whole image. Hoisting the locals to xdata does not help either, - * because itohex() is inline and brings its own frame. */ -void set_hostname_default(void) -{ - if (hostname[0] != NUL) - return; - - strcpy((__xdata uint8_t *)hostname, "RTLPlayground-"); - hostname[14] = hex[uip_ethaddr.addr[3] >> 4]; - hostname[15] = hex[uip_ethaddr.addr[3] & 0xf]; - hostname[16] = hex[uip_ethaddr.addr[4] >> 4]; - hostname[17] = hex[uip_ethaddr.addr[4] & 0xf]; - hostname[18] = hex[uip_ethaddr.addr[5] >> 4]; - hostname[19] = hex[uip_ethaddr.addr[5] & 0xf]; - hostname[20] = NUL; -} void main(void) From 3dfd6a88c77c9d340779e810968cb9e94f703f23 Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Tue, 8 Sep 2026 16:37:28 +0200 Subject: [PATCH 2/3] Move the SFP handling out of the common area into BANK3 sfp.c takes handle_sfp, sfp_module_read, sfp_apply_quirks, sfp_get_info, sfp_read_field, sfp_print_info, setup_sfp_gpio, the quirk table and the module state that goes with them. Everything exported is __banked: handle_sfp() and sfp_print_info() are reached from cmd_parser.c in BANK2, the rest from the common area, and both are bank boundaries. The quirk table needed checking rather than assuming. Its entries are __code pointers, and a __code pointer carries no bank, so passing one to a function in a different bank hands it an offset read through the wrong window. That is safe here because strcmp() sits in the common segment at 0x51f and is reached with a plain lcall, so the bank register still says 3 while it runs. Verified in the built image: the table at 0x35580 holds 0x563c and 0x5644, which resolve to "QSFPTEK" and "QT-SFP+-T" inside BANK3. Common segment 13393 -> 8432 bytes, leaving 7492 free rather than 2531. BANK3 holds 5710, BANK1 is unchanged and BANK2 grows by 31 for the trampolines. All 34 machines in machine.h build and link, and the same walk over the generated assembly finds no plain lcall crossing a bank boundary. --- Makefile | 1 + cmd_parser.c | 4 +- rtl837x_common.h | 2 - rtlplayground.c | 184 +-------------------------------------- sfp.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++ sfp.h | 19 ++++ 6 files changed, 243 insertions(+), 188 deletions(-) create mode 100644 sfp.c create mode 100644 sfp.h diff --git a/Makefile b/Makefile index b577196b..4b0190d2 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,7 @@ SRCS = \ html_data.c \ rtlplayground.c \ boot.c \ + sfp.c \ syslog.c \ udp_apps.c diff --git a/cmd_parser.c b/cmd_parser.c index 5b769a24..5a3a3d60 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -14,6 +14,7 @@ #include "rtl837x_stp.h" #include "rtl837x_igmp.h" #include "rtl837x_bandwidth.h" +#include "sfp.h" #include "dhcp.h" #include "syslog.h" #include "uip/uip.h" @@ -49,9 +50,6 @@ __xdata char port_names[9][PORT_NAME_SIZE]; extern __xdata uint16_t management_vlan; extern __xdata struct uip_eth_addr uip_ethaddr; -extern __xdata uint8_t sfp_speed[2]; -extern __xdata uint8_t sfp_pins_last; -extern __xdata uint8_t sfp_options[2]; __xdata uint8_t gpio_last_value[8] = { 0 }; // Temporatly for str to hex convertion value. diff --git a/rtl837x_common.h b/rtl837x_common.h index 572b4bfb..16380368 100644 --- a/rtl837x_common.h +++ b/rtl837x_common.h @@ -185,10 +185,8 @@ void tcpip_output(void); uint8_t read_flash(uint8_t bank, __code uint8_t *addr); void get_random_32(void); void read_reg_timer(__xdata uint32_t * tmr); -bool sfp_print_info(uint8_t sfp); bool gpio_pin_test(uint8_t pin); void set_sys_led_state(uint8_t state); void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg); void sds_write_v(uint8_t sds_id, uint8_t page, uint8_t reg, uint16_t v); -void handle_sfp(void); #endif diff --git a/rtlplayground.c b/rtlplayground.c index d2346804..b6b15b4b 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -27,6 +27,7 @@ #include "syslog.h" #include "httpd/page_impl.h" #include "boot.h" +#include "sfp.h" extern __code const struct machine machine; extern __xdata uint32_t flash_size; @@ -135,33 +136,10 @@ __code uint16_t bit_mask[16] = { __xdata uint8_t linkbits_last[4]; __xdata uint8_t linkbits_last_p89; // Last known state of the SFP detection/Loss of Signal pins -// SFP1 b0 = 1 => module missing, b1 = 1 => LOS; -// SFP2 b4 = 1 => module missing, b5 = 1 => LOS; -__xdata uint8_t sfp_pins_last; -__xdata char sfp_module_vendor[2][17]; -__xdata char sfp_module_model[2][17]; -__xdata char sfp_module_serial[2][17]; -__xdata uint8_t sfp_options[2]; -__xdata uint8_t sfp_buf[16]; /* scratch for one I2C transaction, the controller reads at most 16 bytes */ -__xdata uint8_t sfp_speed[2]; -__xdata uint8_t sfp_quirks[2]; __xdata bool button_last; __xdata uint8_t button_sec_counter_last; volatile __bit tx_buf_empty; -__code enum sfp_quirk { - SFP_QUIRK_DDM = (1 << 0), -}; - -struct sfp_quirk_entry { - __code char *vendor; // Set vendor or model to 0 to act as wildcard - __code char *model; - uint8_t quirks; -}; - -static __code struct sfp_quirk_entry sfp_quirk_table[] = { - { "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM }, -}; struct eth_in { struct uip_eth_addr dst; @@ -1101,85 +1079,6 @@ void handle_tx(void) } -static inline uint8_t sfp_rate_to_sds_config(uint8_t rate) -{ - if (rate == 0x1 || rate == 0x2) - return SDS_100FX; - if (rate == 0xc || rate == 0xd) - return SDS_1000BX_FIBER; - if (rate >= 0x19 && rate <= 0x20) // Ethernet 2.5 GBit - return SDS_HSG; - if (rate >= 0x62 && rate < 0x70) - return SDS_10GR; - return 0xff; -} - - -bool sfp_print_info(uint8_t sfp) -{ - // This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields - for (uint8_t i = 16; i < 64; i++) { - if (!(i & 0xf) && !sfp_read_block(sfp, i, 16)) - return false; - if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes - continue; - uint8_t c = sfp_buf[i & 0xf]; - if (c) - write_char(c); - } - print_string("\n"); - - return true; -} - -// Normalize strings from EEPROM by removing any trailing spaces; this allows simpler comparisons -bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __reentrant -{ - if (!sfp_read_block(sfp, start, length)) - return false; - - dst[length] = NUL; - memcpy(dst, sfp_buf, length); - - while (length > 0 && dst[--length] == ' ') - dst[length] = NUL; - - return true; -} - -bool sfp_get_info(uint8_t sfp) -{ - if (!sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16)) - return false; - if (!sfp_read_field(sfp_module_model[sfp], sfp, 40, 16)) - return false; - - return sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16); -} - -void sfp_apply_quirks(uint8_t sfp) __reentrant -{ - sfp_quirks[sfp] = 0; - - for (uint8_t i = 0; i < sizeof(sfp_quirk_table) / sizeof(*sfp_quirk_table); i++) { - if (!sfp_quirk_table[i].vendor || !strcmp(sfp_module_vendor[sfp], sfp_quirk_table[i].vendor)) { - if (!sfp_quirk_table[i].model || !strcmp(sfp_module_model[sfp], sfp_quirk_table[i].model)) { - sfp_quirks[sfp] |= sfp_quirk_table[i].quirks; - } - } - } - - if (sfp_quirks[sfp] & SFP_QUIRK_DDM) { - if (!(sfp_options[sfp] & 0x40)) { - // The module reports that DDM is not implemented, but try a dummy read to confirm - // 0xff would mean a failed I2C read or an impossible (per spec) voltage greater than 6.5V - if (sfp_read_block(sfp, 226, 1) && sfp_buf[0] != 0xff) { - sfp_options[sfp] |= 0x40; - } - } - } -} - bool gpio_pin_test(uint8_t pin) { @@ -1187,87 +1086,6 @@ bool gpio_pin_test(uint8_t pin) return sfr_data[3-((pin >> 3) & 3)] & (1 << (pin & 7)); } -/* Inititalize SFP GPIOs */ -void setup_sfp_gpio(void) -{ - for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) { - gpio_input_setup(machine.sfp_port[sfp].pin_detect); - gpio_input_setup(machine.sfp_port[sfp].pin_los); - gpio_output_setup(machine.sfp_port[sfp].pin_tx_disable, 0); - } -} - -static bool sfp_module_read(uint8_t sfp) -{ - uint8_t rate; - - // Read Reg 11: Encoding, see SFF-8472 and SFF-8024 - // Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit - delay(100); // Delay, because some modules need time to wake up - if (!sfp_read_block(sfp, 11, 2)) - return false; - - rate = sfp_buf[1]; - if (sfp_speed[sfp] == SFP_SPEED_100M) - rate = 0x1; - else if (sfp_speed[sfp] == SFP_SPEED_1G) - rate = 0xc; - else if (sfp_speed[sfp] == SFP_SPEED_2G5) - rate = 0x19; - else if (sfp_speed[sfp] == SFP_SPEED_10G) - rate = 0x69; - print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored? - print_string(" Encoding: "); print_byte(sfp_buf[0]); - print_string(" Module: "); - if (!sfp_print_info(sfp)) - return false; - print_string("\n"); - - if (!sfp_read_block(sfp, 92, 1)) - return false; - sfp_options[sfp] = sfp_buf[0]; - if (!sfp_get_info(sfp)) - return false; - - sfp_apply_quirks(sfp); - sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate)); - - return true; -} - - -void handle_sfp(void) -{ - for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) { - if (!gpio_pin_test(machine.sfp_port[sfp].pin_detect)) { - if (sfp_pins_last & (0x1 << (sfp << 2))) { - sfp_pins_last &= ~(0x01 << (sfp << 2)); - print_string("\n Slot: "); write_char('1' + sfp); - if (!sfp_module_read(sfp)) { - print_string("SFP: an I2C read failed, retrying on the next poll\n"); - sfp_pins_last |= 0x01 << (sfp << 2); - } - } - } else { - if (!(sfp_pins_last & (0x1 << (sfp << 2)))) { - sfp_pins_last |= 0x01 << (sfp << 2); - print_string("\n Slot: "); write_char('1' + sfp); write_char('\n'); - } - } - - if (!gpio_pin_test(machine.sfp_port[sfp].pin_los)) { - if (sfp_pins_last & (0x2 << (sfp << 2))) { // 0x2 0x08 - sfp_pins_last &= ~(0x02 << (sfp << 2)); - print_string("\n Slot: "); write_char('1' + sfp); write_char('\n'); - } - } else { - if (!(sfp_pins_last & 0x2 << (sfp << 2))) { - sfp_pins_last |= 0x02 << (sfp << 2); - print_string("\n Slot: "); write_char('1' + sfp); write_char('\n'); - } - } - } -} void flash_default_config(void) { diff --git a/sfp.c b/sfp.c new file mode 100644 index 00000000..7bc4f301 --- /dev/null +++ b/sfp.c @@ -0,0 +1,221 @@ +#pragma codeseg BANK3 +#pragma constseg BANK3 + +#include <8051.h> +#include +#include + +#include "rtl837x_sfr.h" +#include "rtl837x_regs.h" +#include "rtl837x_common.h" +#include "rtl837x_pins.h" +#include "rtl837x_phy.h" +#include "rtl837x_port.h" +#include "machine.h" +#include "phy.h" +#include "boot.h" +#include "sfp.h" + +extern __code const struct machine machine; + +// SFP1 b0 = 1 => module missing, b1 = 1 => LOS; +// SFP2 b4 = 1 => module missing, b5 = 1 => LOS; +__xdata uint8_t sfp_pins_last; +__xdata char sfp_module_vendor[2][17]; +__xdata char sfp_module_model[2][17]; +__xdata char sfp_module_serial[2][17]; +__xdata uint8_t sfp_options[2]; +__xdata uint8_t sfp_buf[16]; /* scratch for one I2C transaction, the controller reads at most 16 bytes */ +__xdata uint8_t sfp_speed[2]; +__xdata uint8_t sfp_quirks[2]; + + +__code enum sfp_quirk { + SFP_QUIRK_DDM = (1 << 0), +}; + +struct sfp_quirk_entry { + __code char *vendor; // Set vendor or model to 0 to act as wildcard + __code char *model; + uint8_t quirks; +}; + +static __code struct sfp_quirk_entry sfp_quirk_table[] = { + { "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM }, +}; + + + + +static inline uint8_t sfp_rate_to_sds_config(uint8_t rate) +{ + if (rate == 0x1 || rate == 0x2) + return SDS_100FX; + if (rate == 0xc || rate == 0xd) + return SDS_1000BX_FIBER; + if (rate >= 0x19 && rate <= 0x20) // Ethernet 2.5 GBit + return SDS_HSG; + if (rate >= 0x62 && rate < 0x70) + return SDS_10GR; + return 0xff; +} + + + + +bool sfp_print_info(uint8_t sfp) __banked +{ + // This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields + for (uint8_t i = 16; i < 64; i++) { + if (!(i & 0xf) && !sfp_read_block(sfp, i, 16)) + return false; + if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes + continue; + uint8_t c = sfp_buf[i & 0xf]; + if (c) + write_char(c); + } + print_string("\n"); + + return true; +} + + +// Normalize strings from EEPROM by removing any trailing spaces; this allows simpler comparisons +bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __banked __reentrant +{ + if (!sfp_read_block(sfp, start, length)) + return false; + + dst[length] = NUL; + memcpy(dst, sfp_buf, length); + + while (length > 0 && dst[--length] == ' ') + dst[length] = NUL; + + return true; +} + + + +bool sfp_get_info(uint8_t sfp) __banked +{ + if (!sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16)) + return false; + if (!sfp_read_field(sfp_module_model[sfp], sfp, 40, 16)) + return false; + + return sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16); +} + + + +void sfp_apply_quirks(uint8_t sfp) __banked __reentrant +{ + sfp_quirks[sfp] = 0; + + for (uint8_t i = 0; i < sizeof(sfp_quirk_table) / sizeof(*sfp_quirk_table); i++) { + if (!sfp_quirk_table[i].vendor || !strcmp(sfp_module_vendor[sfp], sfp_quirk_table[i].vendor)) { + if (!sfp_quirk_table[i].model || !strcmp(sfp_module_model[sfp], sfp_quirk_table[i].model)) { + sfp_quirks[sfp] |= sfp_quirk_table[i].quirks; + } + } + } + + if (sfp_quirks[sfp] & SFP_QUIRK_DDM) { + if (!(sfp_options[sfp] & 0x40)) { + // The module reports that DDM is not implemented, but try a dummy read to confirm + // 0xff would mean a failed I2C read or an impossible (per spec) voltage greater than 6.5V + if (sfp_read_block(sfp, 226, 1) && sfp_buf[0] != 0xff) { + sfp_options[sfp] |= 0x40; + } + } + } +} + + +/* Inititalize SFP GPIOs */ +void setup_sfp_gpio(void) __banked +{ + for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) { + gpio_input_setup(machine.sfp_port[sfp].pin_detect); + gpio_input_setup(machine.sfp_port[sfp].pin_los); + gpio_output_setup(machine.sfp_port[sfp].pin_tx_disable, 0); + } +} + + + +static bool sfp_module_read(uint8_t sfp) +{ + uint8_t rate; + + // Read Reg 11: Encoding, see SFF-8472 and SFF-8024 + // Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit + delay(100); // Delay, because some modules need time to wake up + if (!sfp_read_block(sfp, 11, 2)) + return false; + + rate = sfp_buf[1]; + if (sfp_speed[sfp] == SFP_SPEED_100M) + rate = 0x1; + else if (sfp_speed[sfp] == SFP_SPEED_1G) + rate = 0xc; + else if (sfp_speed[sfp] == SFP_SPEED_2G5) + rate = 0x19; + else if (sfp_speed[sfp] == SFP_SPEED_10G) + rate = 0x69; + print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored? + print_string(" Encoding: "); print_byte(sfp_buf[0]); + print_string(" Module: "); + if (!sfp_print_info(sfp)) + return false; + print_string("\n"); + + if (!sfp_read_block(sfp, 92, 1)) + return false; + sfp_options[sfp] = sfp_buf[0]; + if (!sfp_get_info(sfp)) + return false; + + sfp_apply_quirks(sfp); + sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate)); + + return true; +} + + + + +void handle_sfp(void) __banked +{ + for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) { + if (!gpio_pin_test(machine.sfp_port[sfp].pin_detect)) { + if (sfp_pins_last & (0x1 << (sfp << 2))) { + sfp_pins_last &= ~(0x01 << (sfp << 2)); + print_string("\n Slot: "); write_char('1' + sfp); + if (!sfp_module_read(sfp)) { + print_string("SFP: an I2C read failed, retrying on the next poll\n"); + sfp_pins_last |= 0x01 << (sfp << 2); + } + } + } else { + if (!(sfp_pins_last & (0x1 << (sfp << 2)))) { + sfp_pins_last |= 0x01 << (sfp << 2); + print_string("\n Slot: "); write_char('1' + sfp); write_char('\n'); + } + } + + if (!gpio_pin_test(machine.sfp_port[sfp].pin_los)) { + if (sfp_pins_last & (0x2 << (sfp << 2))) { // 0x2 0x08 + sfp_pins_last &= ~(0x02 << (sfp << 2)); + print_string("\n Slot: "); write_char('1' + sfp); write_char('\n'); + } + } else { + if (!(sfp_pins_last & 0x2 << (sfp << 2))) { + sfp_pins_last |= 0x02 << (sfp << 2); + print_string("\n Slot: "); write_char('1' + sfp); write_char('\n'); + } + } + } +} diff --git a/sfp.h b/sfp.h new file mode 100644 index 00000000..250ce4d6 --- /dev/null +++ b/sfp.h @@ -0,0 +1,19 @@ +#ifndef SFP_H +#define SFP_H + +extern __xdata uint8_t sfp_pins_last; +extern __xdata char sfp_module_vendor[2][17]; +extern __xdata char sfp_module_model[2][17]; +extern __xdata char sfp_module_serial[2][17]; +extern __xdata uint8_t sfp_options[2]; +extern __xdata uint8_t sfp_speed[2]; +extern __xdata uint8_t sfp_quirks[2]; + +bool sfp_print_info(uint8_t sfp) __banked; +bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __banked __reentrant; +bool sfp_get_info(uint8_t sfp) __banked; +void sfp_apply_quirks(uint8_t sfp) __banked __reentrant; +void setup_sfp_gpio(void) __banked; +void handle_sfp(void) __banked; + +#endif From b42eace21d6fa447a7daadb6e2fc8ce8c186bcbe Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Sun, 13 Sep 2026 05:01:14 +0200 Subject: [PATCH 3/3] Declare flash_default_config() in rtl837x_common.h boot.c calls it from BANK3 and only rtlplayground.c had a prototype, so the compiler saw an implicit declaration. The call itself was fine, the function lives in the common area, but the warning was real. Move the prototype into the shared header. Reported by vDorst. --- rtl837x_common.h | 1 + rtlplayground.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl837x_common.h b/rtl837x_common.h index 16380368..ee1c61bb 100644 --- a/rtl837x_common.h +++ b/rtl837x_common.h @@ -189,4 +189,5 @@ bool gpio_pin_test(uint8_t pin); void set_sys_led_state(uint8_t state); void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg); void sds_write_v(uint8_t sds_id, uint8_t page, uint8_t reg, uint16_t v); +void flash_default_config(void); #endif diff --git a/rtlplayground.c b/rtlplayground.c index b6b15b4b..0bb2f0aa 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -35,7 +35,6 @@ extern __xdata uint32_t flash_size; extern __xdata uint16_t crc_value; __xdata struct machine_runtime machine_detected; void crc16_bank1(__xdata uint8_t *v) __naked; -void flash_default_config(void); // See setup_serial_timer1() for valid baudrate settings! #define SERIAL_BAUD_RATE 115200