mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
N-type SOC need to swap some Serdes lines to make it work.
Without this fix N-type SOC devices like RTL8372N, RTL8383N and also the 4-port PHY RTL8224N, don't have a functional Serdes. Although the SOC sees a link, there is no packet flow on both SFP-port nor RTL8224 ports. Added helper functions to read/write to the RTL8224. RTL8224 has the same register layout so we can use the same register defines as for the main SOC.
This commit is contained in:
+98
-5
@@ -8,6 +8,7 @@
|
||||
|
||||
// Phy ID of the external RTL8224 PHY.
|
||||
#define RTL8224_PHY_ID 0x00
|
||||
#define RTL8224_DEV_ID 0x1e
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
@@ -15,14 +16,17 @@
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_phy.h"
|
||||
#include "phy.h"
|
||||
#include "machine.h"
|
||||
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
extern __code uint16_t bit_mask[16];
|
||||
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
|
||||
__code uint16_t rtl8224_ca[42] = {
|
||||
// SDS_DATA, SDS_CMD
|
||||
0x4480, 0xc842,
|
||||
0x0400, 0xc9c2,
|
||||
0x6d02, 0xcc42,
|
||||
@@ -43,6 +47,9 @@ __code uint16_t rtl8224_ca[42] = {
|
||||
0xabb0, 0xcedc,
|
||||
0x5078, 0xc90c,
|
||||
0xc45c, 0xc18c,
|
||||
// Note Swapping the RX for N-device here, don't work
|
||||
// Setting will apply but still no packets flow.
|
||||
// 0x2000, 0xc10c,
|
||||
0, 0
|
||||
};
|
||||
|
||||
@@ -75,19 +82,24 @@ void rtl8224_phy_enable(void) __banked
|
||||
|
||||
// p001e.0a90:00f3 R02f8-000000f3 R02f4-000000fc P000001.1e000a90:00fc
|
||||
print_string("\r\nrtl8224_phy_enable called\r\n");
|
||||
phy_read(RTL8224_PHY_ID, 0x1e, 0xa90);
|
||||
phy_read(RTL8224_PHY_ID, RTL8224_DEV_ID, RTL837X_CFG_PHY_MDI_REVERSE);
|
||||
pval = SFR_DATA_U16;
|
||||
|
||||
// PHY Initialization:
|
||||
REG_WRITE(0x2f8, 0, 0, pval >> 8, pval);
|
||||
|
||||
pval &= 0xfff0;
|
||||
pval |= 0x0c;
|
||||
REG_WRITE(0x2f4, 0, 0, pval >> 8, pval);
|
||||
|
||||
phy_write(RTL8224_PHY_ID, 0x1e, 0xa90, pval);
|
||||
phy_write(RTL8224_PHY_ID, RTL8224_DEV_ID, RTL837X_CFG_PHY_MDI_REVERSE, pval);
|
||||
delay(50);
|
||||
|
||||
if (machine_detected.isN) {
|
||||
print_string(" N-settings");
|
||||
// TX_POLARITY_SWAP
|
||||
rtl8224_write_reg_u16(RTL837X_CFG_PHY_TX_POLARITY_SWAP, 0x596A);
|
||||
}
|
||||
|
||||
print_string("\r\nrtl8224_phy_enable done\r\n");
|
||||
}
|
||||
|
||||
@@ -153,7 +165,15 @@ void phy_config(uint8_t phy) __banked
|
||||
void phy_config_8224(void) __banked
|
||||
{
|
||||
uint16_t pval;
|
||||
print_string("\r\nphy_config_8224 called\r\n");
|
||||
print_string("\r\nphy_config_8224 called\r\nRTL8224 ID: ");
|
||||
|
||||
// Print RTL8224 chip id
|
||||
rtl8224_read_reg_u16(RTL837X_REG_CHIP_ID + 1);
|
||||
print_short(SFR_DATA_U16);
|
||||
rtl8224_read_reg_u16(RTL837X_REG_CHIP_ID);
|
||||
print_byte(SFR_DATA_U16 >> 8);
|
||||
print_byte(SFR_DATA_U16);
|
||||
write_char('\n');
|
||||
|
||||
// p001e.7b20:0bff R02f8-00000bff R02f4-00000bed P000001.1e007b20:0bed
|
||||
phy_read(RTL8224_PHY_ID, 0x1e, 0x7b20);
|
||||
@@ -437,3 +457,76 @@ void phy_reset(uint8_t port) __banked
|
||||
// Re-enable PHY
|
||||
phy_write(port, PHY_MMD_CTRL, 0xa610, v & 0xf7ff);
|
||||
}
|
||||
|
||||
// Read RTL8224 register.
|
||||
// Registers names are the same as on the RTL837x.
|
||||
// Reading only reads the lower 16-bit part of the 32-bit register.
|
||||
// When also needing read the upper 16-bits, use register address + 1.
|
||||
// Readed values it return via sfr-data.
|
||||
void inline rtl8224_read_reg_u16(uint16_t reg) __banked
|
||||
{
|
||||
// void phy_read(uint8_t phy_id, uint8_t dev_id, uint16_t reg)
|
||||
// phy_read(RTL8224_PHY_ID, 0x1e, reg);
|
||||
|
||||
SFR_SMI_REG_U16 = reg; // c2, c2
|
||||
|
||||
SFR_SMI_PHY = RTL8224_PHY_ID; // a5
|
||||
SFR_SMI_DEV = RTL8224_DEV_ID << 3 | 2; // c4
|
||||
|
||||
SFR_EXEC_GO = SFR_EXEC_READ_SMI;
|
||||
do {
|
||||
} while (SFR_EXEC_STATUS != 0);
|
||||
}
|
||||
|
||||
// Write RTL8224 register.
|
||||
// Registers names are the same as on the RTL837x.
|
||||
// Writing only the lower 16-bit part of the 32-bit register.
|
||||
// When also needing to write the upper 16-bits, use register address + 1.
|
||||
void inline rtl8224_write_reg_u16(uint16_t reg, uint16_t val) __banked
|
||||
{
|
||||
SFR_DATA_U16 = val; // SFR_A6, SFR_A7
|
||||
SFR_SMI_REG_U16 = reg; // SFR_C2, SFR_C3
|
||||
|
||||
//void phy_write(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t v)
|
||||
// phy_write(RTL8224_PHY_ID, 0x1e, reg, val);
|
||||
|
||||
uint16_t phy_mask = bit_mask[RTL8224_PHY_ID];
|
||||
|
||||
SFR_SMI_PHYMASK = phy_mask; // SFR_C5
|
||||
SFR_SMI_DEV = (phy_mask >> 8) | RTL8224_DEV_ID << 3 | 2; // SFR_C4: bit 2 can also be set for some option
|
||||
SFR_EXEC_GO = SFR_EXEC_WRITE_SMI;
|
||||
do {
|
||||
} while (SFR_EXEC_STATUS != 0);
|
||||
}
|
||||
|
||||
// // Modify RTL8224 register.
|
||||
// // Registers names are the same as on the RTL837x.
|
||||
// // Modifies only the lower 16-bit part of the 32-bit register.
|
||||
// // When also needing to modifie the upper 16-bits, use register address + 1.
|
||||
// void rtl8224_modify_reg_u16(uint16_t reg, uint16_t clear, uint16_t set) __banked
|
||||
// {
|
||||
// phy_read(RTL8224_PHY_ID, 0x1e, reg);
|
||||
// uint16_t pval = SFR_DATA_U16;
|
||||
// pval &= ~(clear);
|
||||
// pval |= set;
|
||||
// phy_write(RTL8224_PHY_ID, 0x1e, reg, pval);
|
||||
// }
|
||||
|
||||
|
||||
// Write to the RTL8224 SDS registers.
|
||||
void rtl8224_sds_write(uint16_t sds_cmd, uint16_t value) __banked
|
||||
{
|
||||
// Wait for command bit is cleared
|
||||
do {
|
||||
rtl8224_read_reg_u16(RTL837X_SDS_INDACS_CMD);
|
||||
} while (SFR_DATA_8 & 0x80);
|
||||
|
||||
rtl8224_write_reg_u16(RTL837X_SDS_INDACS_WRITE_DATA, value);
|
||||
|
||||
rtl8224_write_reg_u16(RTL837X_SDS_INDACS_CMD, sds_cmd);
|
||||
|
||||
// Wait for command bit is cleared
|
||||
do {
|
||||
rtl8224_read_reg_u16(RTL837X_SDS_INDACS_CMD);
|
||||
} while (SFR_DATA_8 & 0x80);
|
||||
}
|
||||
|
||||
@@ -17,5 +17,15 @@ void phy_set_speed(uint8_t port, uint8_t speed, uint8_t duplex) __banked;
|
||||
void phy_set_duplex(uint8_t port, uint8_t fullduplex) __banked;
|
||||
void phy_show(uint8_t port) __banked;
|
||||
void phy_reset(uint8_t port) __banked;
|
||||
void rtl8224_read_reg_u16(uint16_t reg) __banked;
|
||||
void rtl8224_write_reg_u16(uint16_t reg, uint16_t val) __banked;
|
||||
void rtl8224_sds_write(uint16_t sds_cmd, uint16_t val) __banked;
|
||||
|
||||
#define RTL8224_SDS_WRITE(sds_id, page, reg, v) uint16_t _sdscmd = (uint16_t)(sds_id & 0x01) | (1 << 14) | (1 << 15); \
|
||||
_sdscmd |= (page & 0x3F) << 1; \
|
||||
_sdscmd |= ((uint16_t)(reg & 0x1f)) << 7; \
|
||||
print_string("CMD: "); print_short(_sdscmd); \
|
||||
write_char('-'); print_short(v); \
|
||||
rtl8224_sds_write(_sdscmd, v);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,7 +36,20 @@
|
||||
#define RTL837X_REG_SEC_COUNTER2 0x06f8
|
||||
// Used for counting seconds
|
||||
|
||||
|
||||
/*
|
||||
* SDS
|
||||
*/
|
||||
#define RTL837X_SDS_INDACS_CMD 0x3F8
|
||||
#define RTL837X_SDS_INDACS_WRITE_DATA 0x400
|
||||
#define RTL837X_REG_SDS_MODES 0x7b20
|
||||
|
||||
/*
|
||||
* PHY
|
||||
*/
|
||||
#define RTL837X_CFG_PHY_TX_POLARITY_SWAP 0xA94
|
||||
#define RTL837X_CFG_PHY_MDI_REVERSE 0xA90
|
||||
|
||||
/*
|
||||
* 5 Bits each give the state of the 2 SerDes of the RTL8372
|
||||
* Values are:
|
||||
|
||||
+47
-5
@@ -1403,6 +1403,39 @@ void sds_init(void)
|
||||
REG_WRITE(0x2f4, 0, 0, pval >> 8, pval);
|
||||
|
||||
phy_write_mask(0x1, 0x1e, 0xd, pval);
|
||||
|
||||
if (machine_detected.isN) {
|
||||
uint16_t pval;
|
||||
|
||||
print_string(" N-settings");
|
||||
// Serdes 0 RX PN swap for 64B/66B
|
||||
sds_read(1, 6, 2);
|
||||
pval = SFR_DATA_U16;
|
||||
sds_write_v(1, 6, 2, pval | 0x2000);
|
||||
|
||||
// Serdes 1 RX PN swap for 8B/10B
|
||||
sds_read(1, 0, 0);
|
||||
pval = SFR_DATA_U16;
|
||||
sds_write_v(1, 0, 0, pval | 0x200);
|
||||
|
||||
// Serdes 0 RX PN swap for 64B/66B
|
||||
sds_read(0, 6, 2);
|
||||
pval = SFR_DATA_U16;
|
||||
sds_write_v(0, 6, 2, pval | 0x2000);
|
||||
|
||||
if (machine_detected.isRTL8373) {
|
||||
// RTL8224: Serdes 0 RX PN swap for 64B/66B
|
||||
// We assume that RTL8373N always paired with RTL8224N.
|
||||
// This sds register value is 0x0000 at reset.
|
||||
// So only write to it.
|
||||
RTL8224_SDS_WRITE(0, 6, 2, 0x2000);
|
||||
} else {
|
||||
// Serdes 0 RX PN swap for 8B/10B
|
||||
sds_read(0, 0, 0);
|
||||
pval = SFR_DATA_U16;
|
||||
sds_write_v(0, 0, 0, pval | 0x200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1549,9 +1582,18 @@ void rtl8373_init(void)
|
||||
pval = SFR_DATA_U16;
|
||||
|
||||
// r0a90:000000f3 R0a90-000000fc
|
||||
reg_read_m(0xa90);
|
||||
reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE);
|
||||
sfr_mask_data(0, 0x0f,0x0c);
|
||||
reg_write_m(0xa90);
|
||||
reg_write_m(RTL837X_CFG_PHY_MDI_REVERSE);
|
||||
|
||||
if (machine_detected.isN) {
|
||||
print_string(" TX_POLARITY_SWAP\n");
|
||||
// FOR N-Version: #TX_POLARITY_SWAP
|
||||
reg_read_m(RTL837X_CFG_PHY_TX_POLARITY_SWAP);
|
||||
sfr_data[2] = 0x59;
|
||||
sfr_data[3] = 0x6a;
|
||||
reg_write_m(RTL837X_CFG_PHY_TX_POLARITY_SWAP);
|
||||
}
|
||||
|
||||
rtl8224_phy_enable();
|
||||
|
||||
@@ -1617,9 +1659,9 @@ void rtl8372_init(void)
|
||||
reg_write_m(RTL837X_REG_SDS_MODES);
|
||||
|
||||
// r0a90:000000f3 R0a90-000000fc
|
||||
reg_read_m(0xa90);
|
||||
sfr_mask_data(0, 0x0f,0x0c);
|
||||
reg_write_m(0xa90);
|
||||
reg_read_m(RTL837X_CFG_PHY_MDI_REVERSE);
|
||||
sfr_mask_data(0, 0x0f, 0x0c);
|
||||
reg_write_m(RTL837X_CFG_PHY_MDI_REVERSE);
|
||||
|
||||
// Disable PHYs for configuration
|
||||
phy_write_mask(0xf0,0x1f,0xa610,0x2858);
|
||||
|
||||
Reference in New Issue
Block a user