mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
Merge pull request #424 from DrDoof/refactor/split-sfp-boot
Move the boot and SFP handling out of the common area into BANK3
This commit is contained in:
9 files changed
+742
-631
No files matched your search
@@ -59,6 +59,8 @@ SRCS = \
|
|||||||
dhcp.c \
|
dhcp.c \
|
||||||
html_data.c \
|
html_data.c \
|
||||||
rtlplayground.c \
|
rtlplayground.c \
|
||||||
|
boot.c \
|
||||||
|
sfp.c \
|
||||||
syslog.c \
|
syslog.c \
|
||||||
udp_apps.c
|
udp_apps.c
|
||||||
|
|
||||||
@@ -132,7 +134,7 @@ $(BUILDDIR)/%.rel: %.asm | create_build_dir
|
|||||||
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
||||||
|
|
||||||
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
|
$(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
|
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
|
||||||
objcopy --input-target=ihex -O binary $< $@
|
objcopy --input-target=ihex -O binary $< $@
|
||||||
|
|||||||
@@ -0,0 +1,480 @@
|
|||||||
|
#pragma codeseg BANK3
|
||||||
|
#pragma constseg BANK3
|
||||||
|
|
||||||
|
#include <8051.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
+1
-3
@@ -14,6 +14,7 @@
|
|||||||
#include "rtl837x_stp.h"
|
#include "rtl837x_stp.h"
|
||||||
#include "rtl837x_igmp.h"
|
#include "rtl837x_igmp.h"
|
||||||
#include "rtl837x_bandwidth.h"
|
#include "rtl837x_bandwidth.h"
|
||||||
|
#include "sfp.h"
|
||||||
#include "dhcp.h"
|
#include "dhcp.h"
|
||||||
#include "syslog.h"
|
#include "syslog.h"
|
||||||
#include "uip/uip.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 uint16_t management_vlan;
|
||||||
extern __xdata struct uip_eth_addr uip_ethaddr;
|
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 };
|
__xdata uint8_t gpio_last_value[8] = { 0 };
|
||||||
|
|
||||||
// Temporatly for str to hex convertion value.
|
// Temporatly for str to hex convertion value.
|
||||||
|
|||||||
+1
-4
@@ -185,12 +185,9 @@ void tcpip_output(void);
|
|||||||
uint8_t read_flash(uint8_t bank, __code uint8_t *addr);
|
uint8_t read_flash(uint8_t bank, __code uint8_t *addr);
|
||||||
void get_random_32(void);
|
void get_random_32(void);
|
||||||
void read_reg_timer(__xdata uint32_t * tmr);
|
void read_reg_timer(__xdata uint32_t * tmr);
|
||||||
bool sfp_print_info(uint8_t sfp);
|
|
||||||
bool gpio_pin_test(uint8_t pin);
|
bool gpio_pin_test(uint8_t pin);
|
||||||
void set_sys_led_state(uint8_t state);
|
void set_sys_led_state(uint8_t state);
|
||||||
void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg);
|
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_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 flash_default_config(void);
|
||||||
void sds_config(uint8_t sds, uint8_t mode);
|
|
||||||
void handle_sfp(void);
|
|
||||||
#endif
|
#endif
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "rtl837x_phy.h"
|
#include "rtl837x_phy.h"
|
||||||
#include "phy.h"
|
#include "phy.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
#include "boot.h"
|
||||||
|
|
||||||
extern __xdata uint8_t sfr_data[4];
|
extern __xdata uint8_t sfr_data[4];
|
||||||
extern __code struct machine machine;
|
extern __code struct machine machine;
|
||||||
|
|||||||
+2
-623
@@ -26,6 +26,8 @@
|
|||||||
#include "phy.h"
|
#include "phy.h"
|
||||||
#include "syslog.h"
|
#include "syslog.h"
|
||||||
#include "httpd/page_impl.h"
|
#include "httpd/page_impl.h"
|
||||||
|
#include "boot.h"
|
||||||
|
#include "sfp.h"
|
||||||
|
|
||||||
extern __code const struct machine machine;
|
extern __code const struct machine machine;
|
||||||
extern __xdata uint32_t flash_size;
|
extern __xdata uint32_t flash_size;
|
||||||
@@ -33,8 +35,6 @@ extern __xdata uint32_t flash_size;
|
|||||||
extern __xdata uint16_t crc_value;
|
extern __xdata uint16_t crc_value;
|
||||||
__xdata struct machine_runtime machine_detected;
|
__xdata struct machine_runtime machine_detected;
|
||||||
void crc16_bank1(__xdata uint8_t *v) __naked;
|
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!
|
// See setup_serial_timer1() for valid baudrate settings!
|
||||||
#define SERIAL_BAUD_RATE 115200
|
#define SERIAL_BAUD_RATE 115200
|
||||||
@@ -135,33 +135,10 @@ __code uint16_t bit_mask[16] = {
|
|||||||
__xdata uint8_t linkbits_last[4];
|
__xdata uint8_t linkbits_last[4];
|
||||||
__xdata uint8_t linkbits_last_p89;
|
__xdata uint8_t linkbits_last_p89;
|
||||||
// Last known state of the SFP detection/Loss of Signal pins
|
// 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 bool button_last;
|
||||||
__xdata uint8_t button_sec_counter_last;
|
__xdata uint8_t button_sec_counter_last;
|
||||||
volatile __bit tx_buf_empty;
|
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 eth_in {
|
||||||
struct uip_eth_addr dst;
|
struct uip_eth_addr dst;
|
||||||
@@ -944,33 +921,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
|
// Delay for given number of ticks without doing housekeeping
|
||||||
void delay(uint16_t t)
|
void delay(uint16_t t)
|
||||||
{
|
{
|
||||||
@@ -979,181 +929,6 @@ void delay(uint16_t t)
|
|||||||
PCON |= 1;
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1303,85 +1078,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)
|
bool gpio_pin_test(uint8_t pin)
|
||||||
{
|
{
|
||||||
@@ -1389,87 +1085,6 @@ bool gpio_pin_test(uint8_t pin)
|
|||||||
return sfr_data[3-((pin >> 3) & 3)] & (1 << (pin & 7));
|
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<MODULE INSERTED> 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<MODULE REMOVED> 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<SFP-RX OK> 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<SFP-RX LOS> Slot: "); write_char('1' + sfp); write_char('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void flash_default_config(void)
|
void flash_default_config(void)
|
||||||
{
|
{
|
||||||
@@ -1681,19 +1296,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
|
* Set dividers for a chosen CPU frequency
|
||||||
*/
|
*/
|
||||||
@@ -1816,55 +1418,6 @@ void phy_modify(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t mask, uin
|
|||||||
} while (SFR_EXEC_STATUS != 0);
|
} 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)
|
void set_sys_led_state(uint8_t state)
|
||||||
{
|
{
|
||||||
@@ -1873,88 +1426,7 @@ void set_sys_led_state(uint8_t state)
|
|||||||
reg_write_m(RTL837X_REG_LED_MODE);
|
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.
|
/* Set up serial port 0 using Timer 1 as baudrate generator.
|
||||||
@@ -2008,73 +1480,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)
|
void check_and_flash_update_image(void)
|
||||||
{
|
{
|
||||||
flash_read_jedecid(); // This initializes also __xdata flash_size variable
|
flash_read_jedecid(); // This initializes also __xdata flash_size variable
|
||||||
@@ -2160,32 +1565,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)
|
void main(void)
|
||||||
|
|||||||
@@ -0,0 +1,221 @@
|
|||||||
|
#pragma codeseg BANK3
|
||||||
|
#pragma constseg BANK3
|
||||||
|
|
||||||
|
#include <8051.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#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<MODULE INSERTED> 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<MODULE REMOVED> 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<SFP-RX OK> 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<SFP-RX LOS> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
Reference in new issue
Block a user