LED Control

RTL83xx-based switches typically have a large number of LEDs due to each switch port requiring at least one LED, which typically is bi-color (Green for 1000MBit, Yellow for 100/10MBit) or even tri-color (fail status or PoE). Some switches have two separate LEDs per port, others only one multi-colored LED. For controlling these LEDs, this however does not make any difference. In order to control so many different LEDs, normally a serial bus with PINs LED_CLK (122 on the RTL838x) and LED_DAT (123) is used for the port status LEDs, while a few other LEDs can be controlled directly by the SoC. In particular on the RTL838x SoCs with their very few available GPIOs, this is normally only the System LED. The power led is normally not SoC controllable.

There are several different ways how the LEDs can be controlled by this serial bus. The bus itself can be in SCAN mode (with different LED numbers) or SERIAL mode. In any case the serial information needs to be converted in order to drive the respective LED. There are two different converters found on the RTL83xx boards: 74HC164 shift registers and RTL8231 GPIO expanders. The shift-registers only work with the serial mode, whereas the RTL8231 supports both serial and scan mode. The scan-mode actually is an I2C-like mode, called SMI mode by Realtek.

For the RTL SoCs, the port LEDs are typically automatically controlled by the SoC (ASIC) using the serial bus. The configuration is partially defined by strapping pins, and by several LED control registers. On the RTL839x, the serial interface is initially configured by strapping pins 156 and 157:

The setup of the LED configuration is normally done by U-Boot and does not need to be changed by Linux, unless manual control of the LEDs is necessary, for example if some of the port-LEDs have special purposes. U-Boot configures the LEDs in board/Realtek/switch/rtk/mac/rtl8380/rtl8380_init.c. The configuration values for different boards can be found in boot/u-boot-2011.12/board/Realtek/switch/rtk/conf/. Both the RTL838x and the RTL839x have a LED control register, named RTL83XX_LED_GLB_CTRL, which allows to enable and configure the serial LED interface and control the system LED.

Manual control seems necessary in case where serially connected LEDs are not used as port-leds (such as additional status LEDs for PoE, "cloud connection" and the like). In that case it appears that the setup of all the serial LEDs is too complex to be controlled by the SoC alone. The user needs to disable SoC control over all the serially connected LEDs in that case. On both the RTL839x and RTL838x, software control is enabled by setting the respective bits in the RTL83XX_LED_SW_P_EN_CTRL(port) register. One of these registers holds the settings for 10 ports and 3 bits define the state of the LED:

It is unclear why 2 bits would not be sufficient for this.

LEDs and GPIO expanders on the RTL838x

The power LED can be set to different blinking modes with register RTL8380_LED_MODE_SEL (0xBB001004), bits 2 and 3. Bits 0 and 1 seem to be controlled by strapping and define the way the Power LED is controlled.

RTL8380 external LED and GPIO registers

These registers are at a base address of 0xBB00A000.

Offset Name Description
0x00 LED_GLB_CTRL
0x04 LED_MODE_CTRL
0x08 LED_P_EN_CTRL Bit mask indicating which LEDs are ASIC controlled. Bit position corresponds to the MAC/phy number. Set to 1 to enable the LED output for this phy.
0x0C LED_SW_CTRL
0x10+4×n LED_n_SW_P_EN_CTRL LED index n = {0, 1, 2}. Bit mask indicating which LEDs are controlled by the user. Bit position corresponds to the MAC/phy number. Set to 0 for automatic control, 1 for manual control. The corresponding bit in LED_P_EN_CTRL must also be set for this setting to be effective.
0x1C+4×p LED_SW_P_p_CTRL Port index p = {0, .., 27}
0x8C + 4×i EXT_GPIO_DIR_i_CTRL i = floor(index/32), index = {0, .., 54}
0x94 + 4×i EXT_GPIO_DATA_i_CTRL i = floor(index/32), index = {0, .., 54}
0x9C EXT_GPIO_INDIRECT_ACCESS
0xA0 LED_LOAD_LV1
0xA4 LED_LOAD_LV2
0xA8 LED_LOAD_LV3
0xAC+4×k LED0_LO_STSk_CTRL Low ports LED0 status control
0xB8+4×k LED1_LO_STSk_CTRL Low ports LED1 status control
0xC4+4×k LED2_LO_STSk_CTRL Low ports LED2 status control
0xD0 LED0_HI_STS_CTRL High ports LED0 status control
0xD4 LED1_HI_STS_CTRL High ports LED1 status control
0xD8 LED2_HI_STS_CTRL High ports LED2 status control
0xDC LED_RTCT_CTRL (To confirm) Realtek Cable Test control register
0xE0 EXTRA_GPIO_CTRL
0xE4 EXTRA_GPIO_DIR0
0xE8 EXTRA_GPIO_DIR1
0xEC EXTRA_GPIO_DATA0
0xF0 EXTRA_GPIO_DATA1

Global LED control

The SoCs have been designed with the RTL8231 LED expanders in mind as a first-class citizen. A hardware peripheral is present that can keep track of the state of one (or two on RTL93xx) RTL8231 chip(s). The SoC's have dedicated pins and controllers for this task. For rtl930x C1 `LED_MDC` and C2 `LED_MDIO` For rtl931x, AL18 `LED_MDC` and AK18 `LED_MDIO`. This does require the RTL8231 connected to only function as a LED expander. This should not be confused with the dedicated `EXT_GPIO_MDxx` pins!

Main control register for hardware accelerated LEDs and RTL8231 access.

Bits Field description
0-2 Low port LED mask. Activate an LED output for ports 0-23 by setting the respective bit. 0: no LEDs, 0x1: one LED, 0x3: two active LEDs, 0x7: three active LEDs. LEDs must be activated from LSB to MSB, using e.g. 0x5 to enable LED2 and LED0 may confuse the LED controller.
3-5 High port LED mask. Activate an LED output for ports 24-27 by setting the respective bit. 0: no LEDs, 0x1: one LED, 0x3: two active LEDs, 0x7: three active LEDs. Should have the same value as the low-port configuration, even if the ports aren't used.
6 MDIO-clock duty cycle for LED interface
7-8 Combo Port mode. For board RTL8382M_8218B_INTPHY_8218B_2FIB_1G_DEMO cleared to 0, for all others set to 0x2
9-11 STEP1 Power on LED 2..0
12-14 STEP2 Power on LED 2..0
15 Enable system status LED. Will use GPIO0 (A0) as an output
16-17 System LED mode. 0: off, 1: blink rate 64ms, 2: blink rate 1024ms, 3: on
18 LED Load enable
19-21 External 8231 GPIO enable 2..0
22-23 RTL8231 LED blink time bits 1..0. See also bit 30.
24 RTL8231 buzzer enable
25-27 RTL8231 buzzer frequency selection
28 Buzzer CMD
29 Config 8231
30 RTL8231 LED blink time bit 2

Port LED mode control

Set the LED mode for the low and high ports. Field values can be 0-31 and indicate a state matching condition. "Link" will turn the LED on, "Act" will briefly toggle the LED on link activity, with the default state depending on a "Link" specifier. Any speed specifier will narrow the match down to only those speeds. Activity matches only the link the LED is associated with.

Bits Field description
0-4 LED0 mode for port 0-23
5-9 LED1 mode for port 0-23
1-14 LED2 mode for port 0-23
15-19 LED0 mode for port 24-27
20-24 LED1 mode for port 24-27
25-29 LED2 mode for port 24-27

Port LED user control

28 registers, at offsets (0x1C + 4×port).

Bits Field description Field values
0-2 LED0 control 0: off
1: toggle every 32ms
2: toggle every 64ms
3: toggle every 128ms
4: toggle every 512ms
5: on
6: toggle every 1024ms
7: toggle every 512ms
3-5 LED1 control
6-8 LED2 control

Extra GPIO command register

Usually described as the "indirect access" register EXT_GPIO_INDIRECT_ACCESS, at offset 0x9C. Used to send and receive SMI data frames to an external device. Note that there is no indication of command failure, this has to be determined from the register values.

Bits Field desciption
31-16 Frame data. For write commands, this is the data to be sent when executing the command. For read commands, this is the received data after command execution finishes.
11-7 Number of the register to be accessed.
6-2 Device address. Address of the device to be accessed.
1 Operation bit. Set to 0 for read requests, 1 for write requests.
0 Execute bit. Set to 1 to perform the request. Will self-clear after the command is completed or times out.

Port LED status registers

Up to five 3-bit status fields are packed into half-words. For LED0 for example, MAC 0-19 are in the first two registers (0xAC, 0xB0), MAC 20-23 in third (0xB4), and MAC 24-31 in the fourth/high register (0xD0). The high register divides the eight MAC evenly over both half words, putting four (24-27) in the lowest 16 bit, and four (28-31) in the highest 16 bit.

Bits MAC LED status
0-2 MAC 16*n + 0 for (n < 3)
3-5 MAC 16*n + 1 for (n < 3)
6-8 MAC 16*n + 2 for (n < 3)
9-11 MAC 16*n + 3 for (n < 3)
12-14 MAC 16*n + 4 for (n < 2)
15 reserved
16-18 MAC 16*n + 5 for (n < 2), MAC 16*n + 4 for (n = 3)
19-21 MAC 16*n + 6 for (n < 2), MAC 16*n + 5 for (n = 3)
22-24 MAC 16*n + 7 for (n < 2), MAC 16*n + 6 for (n = 3)
25-27 MAC 16*n + 8 for (n < 2), MAC 16*n + 7 for (n = 3)
28-30 MAC 16*n + 9 for (n < 2)
31 reserved

LEDs on the RTL839x

On the RTL839x RTL8390_LED_GLB_CTRL has the following bits:

Configuration of the automatic control of the LEDs is done on this SoC through defining the function of a port LED. 3 Sets of registers define whether a Port has a Led indicating Copper functionality, Fibre or Combo port. The registers are big endian 2x32 bit registers, named RTL8390_LED_COPR_PMASK_CTRL, RTL8390_LED_FIB_PMASK_CTRL, RTL8390_LED_COMBO_PMASK_CTRL. U-Boot sets them up by copying the following configuration values over (example from a 52 port switch with 4 fibre ports, rtl8393m_demo_board.c):

    .led.led_if_sel = LED_IF_SEL_SERIAL,
    .led.num = 2,
    .led.copr_pmask[0] = 0xFFFFFFFF,
    .led.copr_pmask[1] = 0x000FFFFF,
    .led.fib_pmask[0] = 0x00000000,
    .led.fib_pmask[1] = 0x000F0000,
    .led.led_combo[0] = 0x00000000,
        /* LED definition - set 0 */
    .led.led_definition_set[0].led[0] = 0xA,    /* 10/100Mbps link/act */
    .led.led_definition_set[0].led[1] = 0xF,    /* 1000Mbps link/act */
    .led.led_definition_set[0].led[2] = 0x6,    /* duplex mode */
    /* LED definition selection (per-port) */
    .led.led_copr_set_psel_bit0_pmask[0] = 0x00000000,
    .led.led_copr_set_psel_bit1_pmask[0] = 0x00000000,
    .led.led_copr_set_psel_bit0_pmask[1] = 0x00000000,
    .led.led_copr_set_psel_bit1_pmask[1] = 0x00000000,
    .led.led_fib_set_psel_bit0_pmask[0] = 0x00000000,
    .led.led_fib_set_psel_bit1_pmask[0] = 0x00000000,
    .led.led_fib_set_psel_bit0_pmask[1] = 0x00000000,
    .led.led_fib_set_psel_bit1_pmask[1] = 0x00000000,

RTL8390 register overview

Register base address is 0xBB000000.

Offset Name Description
0x0E4 LEB_GLB_CTRL
0x0E8 LED_SET_2_3_CTRL
0x0EC LED_SET_0_1_CTRL
0x0F0 + 4×k LED_COPR_SET_k_SEL_CTRL k = floor(port/16), port = 0-51
0x100 + 4×k LED_FIB_SET_k_SEL_CTRL k = floor(port/16), port = 0-51
0x110 + 4×k LED_COPR_PMASK_k_CTRL k = floor(port/32), port = 0-51
0x118 + 4×k LED_FIB_PMASK_k_CTRL k = floor(port/32), port = 0-51
0x120 + 4×k LED_COMBO_k_CTRL k = floor(port/32), port = 0-51
0x128 LED_SW_CTRL
0x12C + 4×n LED_SW_P_EN_n_CTRL n = floor(port/10), port = 0-51
0x144 + 4×p LED_SW_P_p_CTRL p = 0-51
0x214 + 4×i EXT_GPIO_DIR_i_CTRL i = floor(index/32), index = 0-56
0x21C + 4×i EXT_GPIO_DATA_i_CTRL i = floor(index/32), index = 0-56
0x224 EXT_GPIO_INDIRECT_ACCESS
0x228 LED_LOAD_LV1_10G
0x22C LED_LOAD_LV2_10G
0x230 LED_LOAD_LV3_10G
0x234 LED_LOAD_LV1_1G
0x238 LED_LOAD_LV2_1G
0x23C LED_LOAD_LV3_1G
0x240 LED_LOAD_LV1_100M
0x244 LED_LOAD_LV2_100M
0x248 LED_LOAD_LV3_100M
0x24C LED_LOAD_LV1_10M
0x250 LED_LOAD_LV2_10M
0x254 LED_LOAD_LV3_10M
0x258 LED_P_LOAD_CTRL
0x25C BUZZER_CTRL RTL8231 buzzer settings shadow register

Port LED user control

52 registers, at offsets (0x144 + 4×port). After making modifications to the registers, the new configuration need to be committed by writing 0x1 to LED_SW_CTRL. This sets the SW_LED_LOAD bit, updates the output, and self-clears afterwards.

Bits Field description Field values
0-2 LED0 (cop0) control 0: off
1: toggle every 32ms
2: toggle every 64ms
3: toggle every 128ms
4: toggle every 256ms
5: toggle every 512ms
6: toggle every 1024ms
7: on
3-5 LED1 (cop1) control
6-8 LED2 (cop2) control
9-11 LED3 (fib0) control
12-14 LED4 (fib1) control
15-17 LED5 (fib2) control

LEDs on the RTL930x

These registers are at a base address of 0xBB00C400.

Offset Name Description
0x00 LED_GLB_CTRL
0x04 LED_PORT_NUM_CTR(port) port: 0-27, 2 bits per port
0x0C LED_SET_3_CTRL
0x10 LED_SET_2_CTRL
0x14 LED_SET_1_CTRL
0x18 LED_SET_0_CTRL
0x1C LED_PORT_COPR_SET_SEL_CTRL(port) port = 0-27, 2 bits per port
0x24 LED_PORT_FIB_SEL_CTRL(port) port = 0-27, 2 bits per port
0x2C LED_PORT_COPR_MASK_CTRL(port) port = 0-27, 2 bits per port
0x30 LED_PORT_FIB_MASK_CTRL(port) port = 0-27, 2 bits per port
0x34 LED_PORT_COMBO_MASK_CTRL(port) port = 0-27, 1 bit per port
0x38 LED_SW_LED_LOAD
0x3c LED_PORT_SW_EN_CTRL(port) port = 0-27, 4 bits per port
0x4c LED_PORT_SW_CTRL(port) port = 0-27, 1 register per port
0xbc LED_INDRT_ACCESS_CTRL standard SMI access register
0xc0 LED_LOAD_LV1_10G
0xc4 LED_LOAD_LV2_10G
0xc8 LED_LOAD_LV3_10G
0xcc LED_LOAD_LV1_2P5G
0xd0 LED_LOAD_LV2_2P5G
0xd4 LED_LOAD_LV3_2P5G
0xd8 LED_LOAD_LV1_1G
0xdc LED_LOAD_LV2_1G
0xe0 LED_LOAD_LV3_1G
0xe4 LED_LOAD_LV1_500M
0xe8 LED_LOAD_LV2_500M
0xec LED_LOAD_LV3_500M
0xf0 LED_LOAD_LV1_100M
0xf4 LED_LOAD_LV2_100M
0xf8 LED_LOAD_LV3_100M
0xfc LED_LOAD_LV1_10M
0x100 LED_LOAD_LV2_10M
0x104 LED_LOAD_LV3_10M
0x108 LED_P_LOAD_CTRL

The extra GPIO block starts at a base address of 0xBB00BE00:

Offset Name Description
0x00 EXT_GPIO_GLB_CTRL
0x04 EXT_GPIO_TRIG_CTRL
0x08 EXT_GPIO_DIR_CTRL_1
0x0c EXT_GPIO_DIR_CTRL_2
0x10 EXT_GPIO_DIR_CTRL_3
0x14 EXT_GPIO_DATA_CTRL_1
0x18 EXT_GPIO_DATA_CTRL_2
0x1c EXT_GPIO_DATA_CTRL_3
0x20 EXT_GPIO_INDRT_ACCESS_CTRL standard SMI access register