realtek: add support for port led configuration on RTL93XX
authorBirger Koblitz <git@birger-koblitz.de>
Wed, 2 Feb 2022 06:29:25 +0000 (07:29 +0100)
committerPaul Spooren <mail@aparcar.org>
Wed, 2 Feb 2022 09:32:58 +0000 (10:32 +0100)
Using the led-set attribute of a port in the dts we allow configuration
of the port leds. Each led-set is being defined in the led-set configuration
of the .dts, giving a specific configuration to steer the port LEDs via a serial
connection.

Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
target/linux/realtek/files-5.10/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h
target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h
target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl930x.c
target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl931x.c

index 9f8b210c44c06b6b116589ced96a7e53a4499fcf..d95e5fb098737779ed9ec07adbb52eb01a03b861 100644 (file)
 #define RTL838X_LED_GLB_CTRL           (0xA000)
 #define RTL839X_LED_GLB_CTRL           (0x00E4)
 #define RTL9302_LED_GLB_CTRL           (0xcc00)
-#define RTL930X_LED_GLB_CTRL           (0xC400)
+#define RTL930X_LED_GLB_CTRL           (0xCC00)
 #define RTL931X_LED_GLB_CTRL           (0x0600)
 
 #define RTL838X_EXT_GPIO_DIR           (0xA08C)
index 2c63885881e917927d34a3af1b0a9f715cc7f088..e2b82a4975f0fe4f406da13f93d1fc20f49c8b1d 100644 (file)
@@ -518,6 +518,7 @@ typedef enum {
 #define RTL931X_ACL_PORT_LOOKUP_CTRL(p)                (0x44F8 + (((p) << 2)))
 
 #define RTL930X_PIE_BLK_PHASE_CTRL             (0xA5A4)
+#define RTL931X_PIE_BLK_PHASE_CTRL             (0x4184)
 
 // PIE actions
 #define PIE_ACT_COPY_TO_PORT   2
@@ -554,6 +555,23 @@ typedef enum {
 #define RTL930X_L3_HW_LU_CTRL                  (0xACC0)
 #define RTL930X_L3_IP_ROUTE_CTRL               0xab44
 
+/* Port LED Control */
+#define RTL930X_LED_PORT_NUM_CTRL(p)           (0xCC04 + (((p >> 4) << 2)))
+#define RTL930X_LED_SET0_0_CTRL                        (0xCC28)
+#define RTL930X_LED_PORT_COPR_SET_SEL_CTRL(p)  (0xCC2C + (((p >> 4) << 2)))
+#define RTL930X_LED_PORT_FIB_SET_SEL_CTRL(p)   (0xCC34 + (((p >> 4) << 2)))
+#define RTL930X_LED_PORT_COPR_MASK_CTRL                (0xCC3C)
+#define RTL930X_LED_PORT_FIB_MASK_CTRL         (0xCC40)
+#define RTL930X_LED_PORT_COMBO_MASK_CTRL       (0xCC44)
+
+#define RTL931X_LED_PORT_NUM_CTRL(p)           (0x0604 + (((p >> 4) << 2)))
+#define RTL931X_LED_SET0_0_CTRL                        (0x0630)
+#define RTL931X_LED_PORT_COPR_SET_SEL_CTRL(p)  (0x0634 + (((p >> 4) << 2)))
+#define RTL931X_LED_PORT_FIB_SET_SEL_CTRL(p)   (0x0644 + (((p >> 4) << 2)))
+#define RTL931X_LED_PORT_COPR_MASK_CTRL                (0x0654)
+#define RTL931X_LED_PORT_FIB_MASK_CTRL         (0x065c)
+#define RTL931X_LED_PORT_COMBO_MASK_CTRL       (0x0664)
+
 #define MAX_VLANS 4096
 #define MAX_LAGS 16
 #define MAX_PRIOS 8
@@ -605,6 +623,7 @@ struct rtl838x_port {
        bool is10G;
        bool is2G5;
        int sds_num;
+       int led_set;
        const struct dsa_port *dp;
 };
 
@@ -1017,6 +1036,7 @@ struct rtl838x_reg {
        void (*set_l3_egress_intf)(int idx, struct rtl838x_l3_intf *intf);
        void (*set_distribution_algorithm)(int group, int algoidx, u32 algomask);
        void (*set_receive_management_action)(int port, rma_ctrl_t type, action_type_t action);
+       void (*led_init)(struct rtl838x_switch_priv *priv);
 };
 
 struct rtl838x_switch_priv {
index abe44549a55e8c705113f007ce4154cf8d79c01b..1083241e63fb46a89de89fca2d3ab7d42b1e793a 100644 (file)
@@ -2400,6 +2400,67 @@ void rtl930x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
        sw_w32(newmask << l3shift, RTL930X_TRK_HASH_CTRL + (algoidx << 2));
 }
 
+static void rtl930x_led_init(struct rtl838x_switch_priv *priv)
+{
+       int i, pos;
+       u32 v, pm = 0, set;
+       u32 setlen;
+       const __be32 *led_set;
+       char set_name[9];
+       struct device_node *node;
+
+       pr_info("%s called\n", __func__);
+       node = of_find_compatible_node(NULL, NULL, "realtek,rtl9300-leds");
+       if (!node) {
+               pr_info("%s No compatible LED node found\n", __func__);
+               return;
+       }
+
+       for (i= 0; i < priv->cpu_port; i++) {
+               pos = (i << 1) % 32;
+               sw_w32_mask(0x3 << pos, 0, RTL930X_LED_PORT_FIB_SET_SEL_CTRL(i));
+               sw_w32_mask(0x3 << pos, 0, RTL930X_LED_PORT_COPR_SET_SEL_CTRL(i));
+
+               if (!priv->ports[i].phy)
+                       continue;
+
+               v = 0x1;
+               if (priv->ports[i].is10G)
+                       v = 0x3;
+               if (priv->ports[i].phy_is_integrated)
+                       v = 0x1;
+               sw_w32_mask(0x3 << pos, v << pos, RTL930X_LED_PORT_NUM_CTRL(i));
+
+               pm |= BIT(i);
+
+               set = priv->ports[i].led_set;
+               sw_w32_mask(0, set << pos, RTL930X_LED_PORT_COPR_SET_SEL_CTRL(i));
+               sw_w32_mask(0, set << pos, RTL930X_LED_PORT_FIB_SET_SEL_CTRL(i));
+       }
+
+       for (i = 0; i < 4; i++) {
+               sprintf(set_name, "led_set%d", i);
+               led_set = of_get_property(node, set_name, &setlen);
+               if (!led_set || setlen != 16)
+                       break;
+               v = be32_to_cpup(led_set) << 16 | be32_to_cpup(led_set + 1);
+               sw_w32(v, RTL930X_LED_SET0_0_CTRL - 4 - i * 8);
+               v = be32_to_cpup(led_set + 2) << 16 | be32_to_cpup(led_set + 3);
+               sw_w32(v, RTL930X_LED_SET0_0_CTRL - i * 8);
+       }
+
+       // Set LED mode to serial (0x1)
+       sw_w32_mask(0x3, 0x1, RTL930X_LED_GLB_CTRL);
+
+       // Set port type masks
+       sw_w32(pm, RTL930X_LED_PORT_COPR_MASK_CTRL);
+       sw_w32(pm, RTL930X_LED_PORT_FIB_MASK_CTRL);
+       sw_w32(pm, RTL930X_LED_PORT_COMBO_MASK_CTRL);
+
+       for (i = 0; i < 24; i++)
+               pr_info("%s %08x: %08x\n",__func__, 0xbb00cc00 + i * 4, sw_r32(0xcc00 + i * 4));
+}
+
 const struct rtl838x_reg rtl930x_reg = {
        .mask_port_reg_be = rtl838x_mask_port_reg,
        .set_port_reg_be = rtl838x_set_port_reg,
@@ -2486,4 +2547,5 @@ const struct rtl838x_reg rtl930x_reg = {
        .set_l3_router_mac = rtl930x_set_l3_router_mac,
        .set_l3_egress_intf = rtl930x_set_l3_egress_intf,
        .set_distribution_algorithm = rtl930x_set_distribution_algorithm,
+       .led_init = rtl930x_led_init,
 };
index c0c8a225a81cc401d59722967729a3c687fb8ae7..9ba120899a31fb3f4e0b17072a0a9c2d2bf381cf 100644 (file)
@@ -1424,7 +1424,7 @@ static void rtl931x_pie_init(struct rtl838x_switch_priv *priv)
        // 4: Ingress Flow Table 3, 5: Egress flow table 0
        for (i = 0; i < priv->n_pie_blocks; i++) {
                int pos = (i % 10) * 3;
-               u32 r = RTL930X_PIE_BLK_PHASE_CTRL + 4 * (i / 10);
+               u32 r = RTL931X_PIE_BLK_PHASE_CTRL + 4 * (i / 10);
 
                if (i < priv->n_pie_blocks / 2)
                        sw_w32_mask(0x7 << pos, 0, r);
@@ -1527,6 +1527,68 @@ void rtl931x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
        sw_w32(newmask << l3shift, RTL931X_TRK_HASH_CTRL + (algoidx << 2));
 }
 
+static void rtl931x_led_init(struct rtl838x_switch_priv *priv)
+{
+       int i, pos;
+       u32 v, set;
+       u64 pm_copper = 0, pm_fiber = 0;
+       u32 setlen;
+       const __be32 *led_set;
+       char set_name[9];
+       struct device_node *node;
+
+       pr_info("%s called\n", __func__);
+       node = of_find_compatible_node(NULL, NULL, "realtek,rtl9300-leds");
+       if (!node) {
+               pr_info("%s No compatible LED node found\n", __func__);
+               return;
+       }
+
+       for (i= 0; i < priv->cpu_port; i++) {
+               pos = (i << 1) % 32;
+               sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_FIB_SET_SEL_CTRL(i));
+               sw_w32_mask(0x3 << pos, 0, RTL931X_LED_PORT_COPR_SET_SEL_CTRL(i));
+
+               if (!priv->ports[i].phy)
+                       continue;
+
+               v = 0x1; // Found on the EdgeCore, but we do not have any HW description
+               sw_w32_mask(0x3 << pos, v << pos, RTL931X_LED_PORT_NUM_CTRL(i));
+
+               if (priv->ports[i].phy_is_integrated)
+               pm_fiber |= BIT_ULL(i);
+                       else
+               pm_copper |= BIT_ULL(i);
+
+               set = priv->ports[i].led_set;
+               sw_w32_mask(0, set << pos, RTL931X_LED_PORT_COPR_SET_SEL_CTRL(i));
+               sw_w32_mask(0, set << pos, RTL931X_LED_PORT_FIB_SET_SEL_CTRL(i));
+       }
+
+       for (i = 0; i < 4; i++) {
+               sprintf(set_name, "led_set%d", i);
+               pr_info(">%s<\n", set_name);
+               led_set = of_get_property(node, set_name, &setlen);
+               if (!led_set || setlen != 16)
+                       break;
+               v = be32_to_cpup(led_set) << 16 | be32_to_cpup(led_set + 1);
+               sw_w32(v, RTL931X_LED_SET0_0_CTRL - 4 - i * 8);
+               v = be32_to_cpup(led_set + 2) << 16 | be32_to_cpup(led_set + 3);
+               sw_w32(v, RTL931X_LED_SET0_0_CTRL - i * 8);
+       }
+
+       // Set LED mode to serial (0x1)
+       sw_w32_mask(0x3, 0x1, RTL931X_LED_GLB_CTRL);
+
+       rtl839x_set_port_reg_le(pm_copper, RTL931X_LED_PORT_COPR_MASK_CTRL);
+       rtl839x_set_port_reg_le(pm_fiber, RTL931X_LED_PORT_FIB_MASK_CTRL);
+       rtl839x_set_port_reg_le(pm_copper | pm_fiber, RTL931X_LED_PORT_COMBO_MASK_CTRL);
+
+       for (i = 0; i < 32; i++)
+               pr_info("%s %08x: %08x\n",__func__, 0xbb000600 + i * 4, sw_r32(0x0600 + i * 4));
+
+}
+
 const struct rtl838x_reg rtl931x_reg = {
        .mask_port_reg_be = rtl839x_mask_port_reg_be,
        .set_port_reg_be = rtl839x_set_port_reg_be,
@@ -1594,5 +1656,6 @@ const struct rtl838x_reg rtl931x_reg = {
        .pie_rule_rm = rtl931x_pie_rule_rm,
        .l2_learning_setup = rtl931x_l2_learning_setup,
        .l3_setup = rtl931x_l3_setup,
+       .led_init = rtl931x_led_init,
 };