diff --git a/rtl837x_common.h b/rtl837x_common.h index b517d35..a60d457 100644 --- a/rtl837x_common.h +++ b/rtl837x_common.h @@ -19,4 +19,7 @@ void sleep(uint16_t t); void write_char(char c); void print_reg(uint16_t reg); uint8_t sfp_read_reg(uint8_t reg); +void reg_bit_set(uint16_t reg_addr, char bit); +void reg_bit_clear(uint16_t reg_addr, char bit); + #endif diff --git a/rtl837x_port.c b/rtl837x_port.c index 10a6069..380ec94 100644 --- a/rtl837x_port.c +++ b/rtl837x_port.c @@ -3,6 +3,8 @@ * This code is in the Public Domain */ +// #define REGDBG + #include #include "rtl837x_common.h" #include "rtl837x_sfr.h" @@ -16,6 +18,158 @@ extern __xdata uint8_t maxPort; extern __xdata uint8_t nSFPPorts; extern __xdata uint8_t sfr_data[4]; +__xdata uint32_t l2_head; + +/* + * Table access registers of the RTL837x + * See e.g. RTL8366/RTL8369 datasheet for explanation + */ +#define RTL837X_TBL_CTRL 0x5cac +/* Bytes in control register: EE EE TT CC: EE: Entry, TT: Table type, CC: Command + * CC: BIT 0: 01: Execute. Bit 1: 1: WRITE, 0: READ + * TT: 04: L2-table, 03: VLAN-table + */ +#define TBL_L2_UNICAST 0x04 + +#define RTL837x_TBL_DATA_0 0x5cb0 +#define RTL837x_L2_LIST_DATA_A 0x5ccc +#define RTL837x_L2_LIST_DATA_B 0x5cd0 +#define RTL837x_L2_LIST_DATA_C 0x5cd4 +#define RTL837x_TBL_DATA_IN_A 0x5cb8 + +#define RTL837x_PVID_BASE_REG 0x4e1c + +void vlan_setup(void) __banked +{ + print_string("\r\nvlan_setup called \r\n"); + + // Initialize VLAN table with VLAN 1 + REG_SET(RTL837x_TBL_DATA_IN_A, 0x0007ffff); + REG_SET(RTL837X_TBL_CTRL, 0x00010303); + do { + reg_read_m(RTL837X_TBL_CTRL); + } while (sfr_data[3] & 0x01); + + // Set PVID 1 for every port. TODO: Skip unused ports! + for (uint8_t i = minPort; i <= maxPort + 1; i++) { // Do this also for the CPU port + print_byte(i); write_char(':'); write_char(' '); + uint16_t reg = RTL837x_PVID_BASE_REG + ((i >> 1) << 2); + print_short(reg); write_char(' '); write_char('B'); write_char('>'); + print_sfr_data(); + reg_read_m(reg); + if (i & 0x1) { + REG_WRITE(reg, sfr_data[0], 0, sfr_data[2] & 0x0f | 0x10, sfr_data[3]); + } else { + REG_WRITE(reg, sfr_data[0], sfr_data[1], sfr_data[2] & 0xf0, 0x01); + } + write_char(' '); write_char('A'); write_char('>'); print_sfr_data(); + + reg_bit_clear(0x6738, i << 1); + reg_bit_clear(0x6738, i << 1 + 1); + reg_bit_set(0x4e18, i); + print_string("\r\n"); + } + + // Enable 4k VLAN + REG_SET(0x4e14, 4); + REG_SET(0x4e30, 0); + REG_SET(0x4e34, 0); + + // Enable VLAN 1 + REG_SET(RTL837x_TBL_DATA_IN_A, 0x0207ffff); + REG_SET(RTL837X_TBL_CTRL, 0x00010303); + do { + reg_read_m(RTL837X_TBL_CTRL); + } while (sfr_data[3] & 0x01); + + print_string("\r\nvlan_setup done \r\n"); +} + +/* + * Forget all dynamic L2 learned entries + */ +uint8_t port_l2_forget(void) __banked +{ + // r53dc:00000000 R53dc-00000000 r53d4:000001ff r53d4:000001ff R53d4-000101ff r53d4:000001ff + reg_read_m(0x53dc); + if (sfr_data[0] || sfr_data[1] ||sfr_data[2] ||sfr_data[3]) { + print_string("List busy\r\n"); + return -1; + } + REG_WRITE(0x53dc, sfr_data[0], sfr_data[1], sfr_data[2], sfr_data[3]); + + reg_read_m(0x53d4); + REG_WRITE(0x53d4, 0x00, 0x01, sfr_data[2], sfr_data[3]); + do { + reg_read_m(0x53d4); + } while (sfr_data[1] & 0x1); + + return 0; +} + + +void port_l2_learned(void) __banked +{ + // Whait for any table action to be finished + do { + reg_read_m(RTL837X_TBL_CTRL); + } while (sfr_data[3] & 0x01); + print_string("\r\n\tMAC\t\tVLAN\ttype\tport\r\n"); + uint16_t entry = 0x0000; + uint16_t first_entry = 0xffff; // Table does not have that many entries + + while (1) { + uint8_t port = 0; + reg_read_m(RTL837x_TBL_DATA_0); + REG_WRITE(RTL837x_TBL_DATA_0, sfr_data[0], sfr_data[1],sfr_data[2] | 0xc0, sfr_data[3]); + + REG_WRITE(RTL837X_TBL_CTRL, entry >> 8, entry, TBL_L2_UNICAST, 0x1); + do { + reg_read_m(RTL837X_TBL_CTRL); + } while (sfr_data[3] & 0x1); + + // MAC + reg_read_m(RTL837x_L2_LIST_DATA_B); + print_byte(sfr_data[2]); write_char(':'); + print_byte(sfr_data[3]); write_char(':'); + port = (sfr_data[0] >> 6) & 0x3; + reg_read_m(RTL837x_L2_LIST_DATA_A); + print_byte(sfr_data[0]); write_char(':'); + print_byte(sfr_data[1]); write_char(':'); + print_byte(sfr_data[2]); write_char(':'); + print_byte(sfr_data[3]); write_char('\t'); + + // VLAN + reg_read_m(RTL837x_L2_LIST_DATA_B); + print_short( ((uint16_t) (sfr_data[0] & 0x0f)) | sfr_data[1]); // VLAN + + // type + reg_read_m(RTL837x_L2_LIST_DATA_C); + if (sfr_data[2] & 0x1) + print_string("\tstatic\t"); + else + print_string("\tlearned\t"); + + port |= (sfr_data[3] & 0x3) << 2; + if (port < 9) + write_char('1' + port); + else + print_string("10"); + + reg_read_m(RTL837x_TBL_DATA_0); + entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3] + 1; + if (first_entry == 0xffff) { + first_entry = entry; + } else { + if (first_entry == entry) + break; + } + print_string("\r\n"); + } + print_string("\r\nport_l2_learned done \r\n"); +} + + void port_stats_print(void) __banked { print_string("\r\n Port\tState\tLink\tTxGood\t\tTxBad\t\tRxGood\t\tRxBad\r\n"); @@ -69,8 +223,7 @@ void port_stats_print(void) __banked print_string("Up\t"); } } - // R0f60-000005e1 r0f60:000005e0 r0f64:00000000 r0f68:000000ba r1250:0fffffff R0f60-00000601 r0f60:00000600 r0f64:00000000 r0f68:00000000 - // R0f60-000005c1 r0f60:000005c0 r0f64:00000000 r0f68:000016dd R0f60-00000601 r0f60:00000600 r0f64:00000000 r0f68:00000000 + REG_WRITE(RTL837X_STAT_GET, 0x00, 0x00, 0x05, 0xe0 | (i << 1) | 1); do { reg_read_m(RTL837X_STAT_GET); diff --git a/rtl837x_port.h b/rtl837x_port.h index 1611249..bf57195 100644 --- a/rtl837x_port.h +++ b/rtl837x_port.h @@ -1,6 +1,9 @@ #ifndef _RTL837X_PORT_H_ #define _RTL837X_PORT_H_ +uint8_t port_l2_forget(void) __banked; +void port_l2_learned(void) __banked; void port_stats_print(void) __banked; +void vlan_setup(void) __banked; #endif diff --git a/rtlplayground.c b/rtlplayground.c index 5727a98..a6ad672 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -1594,6 +1594,8 @@ void bootloader(void) rtl8372_init(); REG_SET(0x7f94, 0x0); // BUG: Only for testing, otherwise: clear bits 0-3 nic_setup(); + vlan_setup(); + was_offline = 1; setup_i2c(); @@ -1729,6 +1731,9 @@ void bootloader(void) phy_set_mode(p, PHY_OFF, 0, 0); } } + if (cmd_compare(0, "l2")) { + port_l2_learned(); + } } print_string("\r\n> "); }