88LOG_MODULE_REGISTER (dsa_netc , CONFIG_ETHERNET_LOG_LEVEL );
99
1010#include <zephyr/net/dsa_core.h>
11+ #include <zephyr/net/dsa_tag_netc.h>
1112#include <zephyr/drivers/pinctrl.h>
1213#include <zephyr/drivers/ethernet/nxp_imx_netc.h>
1314#include <zephyr/dt-bindings/ethernet/dsa_tag_proto.h>
@@ -37,10 +38,18 @@ struct dsa_netc_data {
3738 swt_config_t swt_config ;
3839 swt_handle_t swt_handle ;
3940 netc_cmd_bd_t * cmd_bd ;
41+ #ifdef CONFIG_NET_L2_PTP
42+ uint8_t cpu_port_idx ;
43+ struct k_fifo tx_ts_queue ;
44+ #endif
4045};
4146
4247static int dsa_netc_port_init (const struct device * dev )
4348{
49+ #ifdef CONFIG_NET_L2_PTP
50+ struct net_if * iface = net_if_lookup_by_dev (dev );
51+ struct ethernet_context * eth_ctx = net_if_l2_data (iface );
52+ #endif
4453 const struct dsa_port_config * cfg = dev -> config ;
4554 struct dsa_netc_port_config * prv_cfg = cfg -> prv_config ;
4655 struct dsa_switch_context * dsa_switch_ctx = dev -> data ;
@@ -67,6 +76,16 @@ static int dsa_netc_port_init(const struct device *dev)
6776 swt_config -> bridgeCfg .dVFCfg .portMembership |= (1 << cfg -> port_idx );
6877 swt_config -> ports [cfg -> port_idx ].bridgeCfg .enMacStationMove = true;
6978
79+ #ifdef CONFIG_NET_L2_PTP
80+ /* Enable ingress port filter on user ports */
81+ if (eth_ctx -> dsa_port == DSA_CPU_PORT ) {
82+ prv -> cpu_port_idx = cfg -> port_idx ;
83+ swt_config -> ports [cfg -> port_idx ].commonCfg .ipfCfg .enIPFTable = false;
84+ } else {
85+ swt_config -> ports [cfg -> port_idx ].commonCfg .ipfCfg .enIPFTable = true;
86+ }
87+ #endif
88+
7089 return 0 ;
7190}
7291
@@ -79,6 +98,9 @@ static int dsa_netc_switch_setup(const struct dsa_switch_context *dsa_switch_ctx
7998{
8099 struct dsa_netc_data * prv = PRV_DATA (dsa_switch_ctx );
81100 swt_config_t * swt_config = & prv -> swt_config ;
101+ #ifdef CONFIG_NET_L2_PTP
102+ uint32_t entry_id = 0 ;
103+ #endif
82104 status_t result ;
83105
84106 swt_config -> cmdRingUse = 1U ;
@@ -90,6 +112,29 @@ static int dsa_netc_switch_setup(const struct dsa_switch_context *dsa_switch_ctx
90112 return - EIO ;
91113 }
92114
115+ #ifdef CONFIG_NET_L2_PTP
116+ /*
117+ * For gPTP, switch should work as time-aware bridge.
118+ * Trap gPTP frames to cpu port to perform gPTP protocol.
119+ */
120+ netc_tb_ipf_config_t ipf_entry_cfg = {
121+ .keye .etherType = htons (NET_ETH_PTYPE_PTP ),
122+ .keye .etherTypeMask = 0xffff ,
123+ .keye .srcPort = 0 ,
124+ .keye .srcPortMask = 0x0 ,
125+ .cfge .fltfa = kNETC_IPFRedirectToMgmtPort ,
126+ .cfge .hr = kNETC_SoftwareDefHR0 ,
127+ .cfge .timecape = 1 ,
128+ .cfge .rrt = 1 ,
129+ };
130+
131+ result = SWT_RxIPFAddTableEntry (& prv -> swt_handle , & ipf_entry_cfg , & entry_id );
132+ if ((result != kStatus_Success ) || (entry_id == 0xFFFFFFFF )) {
133+ return - EIO ;
134+ }
135+
136+ k_fifo_init (& prv -> tx_ts_queue );
137+ #endif
93138 return 0 ;
94139}
95140
@@ -118,6 +163,70 @@ static void dsa_netc_port_phylink_change(const struct device *phydev, struct phy
118163 }
119164}
120165
166+ #ifdef CONFIG_NET_L2_PTP
167+ static int dsa_netc_port_txtstamp (const struct device * dev , struct net_pkt * pkt )
168+ {
169+ struct dsa_switch_context * dsa_switch_ctx = dev -> data ;
170+ struct dsa_netc_data * prv = PRV_DATA (dsa_switch_ctx );
171+ static uint8_t id = 1 ;
172+
173+ /* Utilize control block for timestamp request ID. */
174+ if (id == 16 ) {
175+ id = 0 ;
176+ }
177+
178+ pkt -> cb .cb [0 ] = id ;
179+ id ++ ;
180+
181+ k_fifo_put (& prv -> tx_ts_queue , pkt );
182+ net_pkt_ref (pkt );
183+
184+ return 0 ;
185+ }
186+
187+ static void dsa_netc_twostep_timestamp_handler (const struct dsa_switch_context * ctx ,
188+ uint8_t ts_req_id , uint64_t ts )
189+ {
190+ struct dsa_netc_data * prv = PRV_DATA (ctx );
191+ struct net_pkt * pkt = k_fifo_get (& prv -> tx_ts_queue , K_NO_WAIT );
192+
193+ while (pkt != NULL ) {
194+
195+ /* Find the matched timestamp */
196+ if (pkt -> cb .cb [0 ] == ts_req_id ) {
197+ pkt -> timestamp .nanosecond = ts % NSEC_PER_SEC ;
198+ pkt -> timestamp .second = ts / NSEC_PER_SEC ;
199+ net_if_call_timestamp_cb (pkt );
200+ net_pkt_unref (pkt );
201+ return ;
202+ /* Enqueue back */
203+ } else {
204+ k_fifo_put (& prv -> tx_ts_queue , pkt );
205+ }
206+
207+ /* Try next */
208+ pkt = k_fifo_get (& prv -> tx_ts_queue , K_NO_WAIT );
209+ }
210+ }
211+ #endif
212+
213+ static struct dsa_tag_netc_data dsa_netc_tag_data = {
214+ #ifdef CONFIG_NET_L2_PTP
215+ .twostep_timestamp_handler = dsa_netc_twostep_timestamp_handler ,
216+ #endif
217+ };
218+
219+ static int dsa_netc_connect_tag_protocol (struct dsa_switch_context * dsa_switch_ctx ,
220+ int tag_proto )
221+ {
222+ if (tag_proto == DSA_TAG_PROTO_NETC ) {
223+ dsa_switch_ctx -> tagger_data = (void * )(& dsa_netc_tag_data );
224+ return 0 ;
225+ }
226+
227+ return - EIO ;
228+ }
229+
121230static int dsa_netc_switch_init (const struct device * dev )
122231{
123232 DEVICE_MMIO_NAMED_MAP (dev , base , K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP );
@@ -131,6 +240,10 @@ static struct dsa_api dsa_netc_api = {
131240 .port_generate_random_mac = dsa_netc_port_generate_random_mac ,
132241 .switch_setup = dsa_netc_switch_setup ,
133242 .port_phylink_change = dsa_netc_port_phylink_change ,
243+ #ifdef CONFIG_NET_L2_PTP
244+ .port_txtstamp = dsa_netc_port_txtstamp ,
245+ #endif
246+ .connect_tag_protocol = dsa_netc_connect_tag_protocol ,
134247};
135248
136249#define DSA_NETC_PORT_INST_INIT (port , n ) \
@@ -149,6 +262,8 @@ static struct dsa_api dsa_netc_api = {
149262 .phy_mode = DT_PROP_OR(port, phy_connection_type, ""), \
150263 .tag_proto = DT_PROP_OR(port, dsa_tag_protocol, DSA_TAG_PROTO_NOTAG), \
151264 .ethernet_connection = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(port, ethernet)), \
265+ IF_ENABLED(CONFIG_PTP_CLOCK_NXP_NETC, \
266+ (.ptp_clock = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(port, ptp_clock)),)) \
152267 .prv_config = &dsa_netc_##n##_##port##_config, \
153268 }; \
154269 DSA_PORT_INST_INIT(port, n, &dsa_##n##_##port##_config)
0 commit comments