realtek: add support for port led configuration on RTL93XX
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>
This commit is contained in:
		 Birger Koblitz
					Birger Koblitz
				
			
				
					committed by
					
						 Daniel Golle
						Daniel Golle
					
				
			
			
				
	
			
			
			 Daniel Golle
						Daniel Golle
					
				
			
						parent
						
							caaac9ab3b
						
					
				
				
					commit
					0538dc693b
				
			| @@ -229,7 +229,7 @@ | ||||
| #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) | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| #include <net/netevent.h> | ||||
| #include <linux/inetdevice.h> | ||||
| #include <linux/rhashtable.h> | ||||
| #include <linux/of_net.h> | ||||
|  | ||||
| #include <asm/mach-rtl838x/mach-rtl83xx.h> | ||||
| #include "rtl83xx.h" | ||||
| @@ -310,6 +311,9 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) | ||||
| 	} | ||||
|  | ||||
| 	for_each_node_by_name(dn, "port") { | ||||
| 		phy_interface_t interface; | ||||
| 		u32 led_set; | ||||
|  | ||||
| 		if (of_property_read_u32(dn, "reg", &pn)) | ||||
| 			continue; | ||||
|  | ||||
| @@ -321,6 +325,28 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		pr_info("%s port %d has phandle\n", __func__, pn); | ||||
| 		if (of_property_read_u32(phy_node, "sds", &priv->ports[pn].sds_num)) | ||||
| 			priv->ports[pn].sds_num = -1; | ||||
| 		else { | ||||
| 			pr_info("%s sds port %d is %d\n", __func__, pn, | ||||
| 				priv->ports[pn].sds_num); | ||||
| 		} | ||||
| 		pr_info("%s port %d has SDS\n", __func__, priv->ports[pn].sds_num); | ||||
|  | ||||
| 		if (of_get_phy_mode(dn, &interface)) | ||||
| 			interface = PHY_INTERFACE_MODE_NA; | ||||
| 		if (interface == PHY_INTERFACE_MODE_HSGMII) | ||||
| 			priv->ports[pn].is2G5 = true; | ||||
| 		if (interface == PHY_INTERFACE_MODE_USXGMII) | ||||
| 			priv->ports[pn].is2G5 = priv->ports[pn].is10G = true; | ||||
| 		if (interface == PHY_INTERFACE_MODE_10GBASER) | ||||
| 			priv->ports[pn].is10G = true; | ||||
|  | ||||
| 		if (of_property_read_u32(dn, "led-set", &led_set)) | ||||
| 			led_set = 0; | ||||
| 		priv->ports[pn].led_set = led_set; | ||||
|  | ||||
| 		// Check for the integrated SerDes of the RTL8380M first | ||||
| 		if (of_property_read_bool(phy_node, "phy-is-integrated") | ||||
| 		    && priv->id == 0x8380 && pn >= 24) { | ||||
| @@ -356,12 +382,6 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// TODO: Do this needs to come from the .dts | ||||
| 	if (priv->family_id == RTL9300_FAMILY_ID) { | ||||
| 		priv->ports[24].is2G5 = true; | ||||
| 		priv->ports[25].is2G5 = true; | ||||
| 	} | ||||
|  | ||||
| 	/* Disable MAC polling the PHY so that we can start configuration */ | ||||
| 	priv->r->set_port_reg_le(0ULL, priv->r->smi_poll_ctrl); | ||||
|  | ||||
|   | ||||
| @@ -258,6 +258,8 @@ static int rtl93xx_setup(struct dsa_switch *ds) | ||||
|  | ||||
| 	priv->r->pie_init(priv); | ||||
|  | ||||
| 	priv->r->led_init(priv); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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, | ||||
| }; | ||||
|   | ||||
| @@ -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, | ||||
| }; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user