1 /*
2  * Copyright 2025 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_dsa_port, CONFIG_NET_DSA_LOG_LEVEL);
9 
10 #include <zephyr/net/ethernet.h>
11 #include <zephyr/net/phy.h>
12 #include <zephyr/net/dsa_core.h>
13 #include "dsa_tag.h"
14 
15 #if defined(CONFIG_NET_INTERFACE_NAME_LEN)
16 #define INTERFACE_NAME_LEN CONFIG_NET_INTERFACE_NAME_LEN
17 #else
18 #define INTERFACE_NAME_LEN 10
19 #endif
20 
dsa_port_initialize(const struct device * dev)21 int dsa_port_initialize(const struct device *dev)
22 {
23 	const struct dsa_port_config *cfg = dev->config;
24 	struct dsa_switch_context *dsa_switch_ctx = dev->data;
25 	struct net_if *iface = net_if_lookup_by_dev(dev);
26 	struct ethernet_context *eth_ctx = net_if_l2_data(iface);
27 	struct ethernet_context *eth_ctx_conduit = NULL;
28 	int err = 0;
29 
30 	dsa_switch_ctx->init_ports++;
31 
32 	/* Find the connection of conduit port and cpu port */
33 	if (dsa_switch_ctx->iface_conduit == NULL && cfg->ethernet_connection != NULL) {
34 		dsa_switch_ctx->iface_conduit = net_if_lookup_by_dev(cfg->ethernet_connection);
35 		if (dsa_switch_ctx->iface_conduit == NULL) {
36 			LOG_ERR("DSA: Conduit iface NOT found!");
37 		}
38 
39 		/* Set up tag protocol on the cpu port */
40 		eth_ctx->dsa_port = DSA_CPU_PORT;
41 		dsa_tag_setup(dev);
42 
43 		/* Provide DSA information to the conduit port */
44 		eth_ctx_conduit = net_if_l2_data(dsa_switch_ctx->iface_conduit);
45 		eth_ctx_conduit->dsa_switch_ctx = dsa_switch_ctx;
46 		eth_ctx_conduit->dsa_port = DSA_CONDUIT_PORT;
47 	}
48 
49 	if (cfg->ethernet_connection == NULL) {
50 		eth_ctx->dsa_port = DSA_USER_PORT;
51 		eth_ctx->dsa_switch_ctx = dsa_switch_ctx;
52 		dsa_switch_ctx->iface_user[cfg->port_idx] = iface;
53 	}
54 
55 	if (dsa_switch_ctx->dapi->port_init != NULL) {
56 		err = dsa_switch_ctx->dapi->port_init(dev);
57 		if (err != 0) {
58 			goto out;
59 		}
60 	}
61 
62 out:
63 	/* All ports are initialized. May need switch setup. */
64 	if (dsa_switch_ctx->init_ports == dsa_switch_ctx->num_ports) {
65 		if (dsa_switch_ctx->dapi->switch_setup != NULL) {
66 			err = dsa_switch_ctx->dapi->switch_setup(dsa_switch_ctx);
67 		}
68 	}
69 
70 	return err;
71 }
72 
dsa_port_iface_init(struct net_if * iface)73 static void dsa_port_iface_init(struct net_if *iface)
74 {
75 	const struct device *dev = net_if_get_device(iface);
76 	struct dsa_port_config *cfg = (struct dsa_port_config *)dev->config;
77 	struct dsa_switch_context *dsa_switch_ctx = dev->data;
78 	char name[INTERFACE_NAME_LEN];
79 
80 	/* Set interface name */
81 	snprintf(name, sizeof(name), "swp%d", cfg->port_idx);
82 	net_if_set_name(iface, name);
83 
84 	/* Use random mac address if could */
85 	if (cfg->use_random_mac_addr && dsa_switch_ctx->dapi->port_generate_random_mac != NULL) {
86 		dsa_switch_ctx->dapi->port_generate_random_mac(cfg->mac_addr);
87 	}
88 
89 	net_if_set_link_addr(iface, cfg->mac_addr, sizeof(cfg->mac_addr), NET_LINK_ETHERNET);
90 
91 	if (cfg->ethernet_connection != NULL) {
92 		net_if_carrier_off(iface);
93 		return;
94 	}
95 
96 	/*
97 	 * Initialize ethernet context 'work' for this iface to
98 	 * be able to monitor the carrier status.
99 	 */
100 	ethernet_init(iface);
101 
102 	/* Do not start the interface until link is up */
103 	net_if_carrier_off(iface);
104 
105 	if (!device_is_ready(cfg->phy_dev)) {
106 		LOG_ERR("PHY device (%p) is not ready, cannot init iface", cfg->phy_dev);
107 		return;
108 	}
109 
110 	if (dsa_switch_ctx->dapi->port_phylink_change == NULL) {
111 		LOG_ERR("require port_phylink_change callback");
112 		return;
113 	}
114 
115 	phy_link_callback_set(cfg->phy_dev, dsa_switch_ctx->dapi->port_phylink_change, (void *)dev);
116 }
117 
dsa_port_get_phy(const struct device * dev)118 static const struct device *dsa_port_get_phy(const struct device *dev)
119 {
120 	const struct dsa_port_config *cfg = dev->config;
121 
122 	return cfg->phy_dev;
123 }
124 
125 const struct ethernet_api dsa_eth_api = {
126 	.iface_api.init = dsa_port_iface_init,
127 	.get_phy = dsa_port_get_phy,
128 	.send = dsa_xmit,
129 };
130