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)