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
+2
-623
@@ -26,6 +26,8 @@
|
||||
#include "phy.h"
|
||||
#include "syslog.h"
|
||||
#include "httpd/page_impl.h"
|
||||
#include "boot.h"
|
||||
#include "sfp.h"
|
||||
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint32_t flash_size;
|
||||
@@ -33,8 +35,6 @@ extern __xdata uint32_t flash_size;
|
||||
extern __xdata uint16_t crc_value;
|
||||
__xdata struct machine_runtime machine_detected;
|
||||
void crc16_bank1(__xdata uint8_t *v) __naked;
|
||||
void flash_default_config(void);
|
||||
void early_boot_handle_button(void);
|
||||
|
||||
// See setup_serial_timer1() for valid baudrate settings!
|
||||
#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_p89;
|
||||
// Last known state of the SFP detection/Loss of Signal pins
|
||||
// SFP1 b0 = 1 => module missing, b1 = 1 => LOS;
|
||||
// SFP2 b4 = 1 => module missing, b5 = 1 => LOS;
|
||||
__xdata uint8_t sfp_pins_last;
|
||||
__xdata char sfp_module_vendor[2][17];
|
||||
__xdata char sfp_module_model[2][17];
|
||||
__xdata char sfp_module_serial[2][17];
|
||||
__xdata uint8_t sfp_options[2];
|
||||
__xdata uint8_t sfp_buf[16]; /* scratch for one I2C transaction, the controller reads at most 16 bytes */
|
||||
__xdata uint8_t sfp_speed[2];
|
||||
__xdata uint8_t sfp_quirks[2];
|
||||
__xdata bool button_last;
|
||||
__xdata uint8_t button_sec_counter_last;
|
||||
volatile __bit tx_buf_empty;
|
||||
|
||||
__code enum sfp_quirk {
|
||||
SFP_QUIRK_DDM = (1 << 0),
|
||||
};
|
||||
|
||||
struct sfp_quirk_entry {
|
||||
__code char *vendor; // Set vendor or model to 0 to act as wildcard
|
||||
__code char *model;
|
||||
uint8_t quirks;
|
||||
};
|
||||
|
||||
static __code struct sfp_quirk_entry sfp_quirk_table[] = {
|
||||
{ "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM },
|
||||
};
|
||||
|
||||
struct eth_in {
|
||||
struct uip_eth_addr dst;
|
||||
@@ -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
|
||||
void delay(uint16_t t)
|
||||
{
|
||||
@@ -979,181 +929,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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -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)
|
||||
{
|
||||
@@ -1389,87 +1085,6 @@ bool gpio_pin_test(uint8_t pin)
|
||||
return sfr_data[3-((pin >> 3) & 3)] & (1 << (pin & 7));
|
||||
}
|
||||
|
||||
/* Inititalize SFP GPIOs */
|
||||
void setup_sfp_gpio(void)
|
||||
{
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
gpio_input_setup(machine.sfp_port[sfp].pin_detect);
|
||||
gpio_input_setup(machine.sfp_port[sfp].pin_los);
|
||||
gpio_output_setup(machine.sfp_port[sfp].pin_tx_disable, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static bool sfp_module_read(uint8_t sfp)
|
||||
{
|
||||
uint8_t rate;
|
||||
|
||||
// Read Reg 11: Encoding, see SFF-8472 and SFF-8024
|
||||
// Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit
|
||||
delay(100); // Delay, because some modules need time to wake up
|
||||
if (!sfp_read_block(sfp, 11, 2))
|
||||
return false;
|
||||
|
||||
rate = sfp_buf[1];
|
||||
if (sfp_speed[sfp] == SFP_SPEED_100M)
|
||||
rate = 0x1;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_1G)
|
||||
rate = 0xc;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_2G5)
|
||||
rate = 0x19;
|
||||
else if (sfp_speed[sfp] == SFP_SPEED_10G)
|
||||
rate = 0x69;
|
||||
print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored?
|
||||
print_string(" Encoding: "); print_byte(sfp_buf[0]);
|
||||
print_string(" Module: ");
|
||||
if (!sfp_print_info(sfp))
|
||||
return false;
|
||||
print_string("\n");
|
||||
|
||||
if (!sfp_read_block(sfp, 92, 1))
|
||||
return false;
|
||||
sfp_options[sfp] = sfp_buf[0];
|
||||
if (!sfp_get_info(sfp))
|
||||
return false;
|
||||
|
||||
sfp_apply_quirks(sfp);
|
||||
sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void handle_sfp(void)
|
||||
{
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
if (!gpio_pin_test(machine.sfp_port[sfp].pin_detect)) {
|
||||
if (sfp_pins_last & (0x1 << (sfp << 2))) {
|
||||
sfp_pins_last &= ~(0x01 << (sfp << 2));
|
||||
print_string("\n<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)
|
||||
{
|
||||
@@ -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
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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 +1426,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 +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)
|
||||
{
|
||||
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)
|
||||
|
||||
Reference in new issue
Block a user