1 /*
2  * Copyright 2024-2025 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_imx_netc_psi
8 
9 #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(nxp_imx_eth_psi);
12 
13 #include <zephyr/kernel.h>
14 #include <zephyr/device.h>
15 #include <zephyr/drivers/pinctrl.h>
16 #include <zephyr/net/ethernet.h>
17 #include <zephyr/net/net_if.h>
18 #include <zephyr/net/net_pkt.h>
19 #include <zephyr/net/phy.h>
20 #include <ethernet/eth_stats.h>
21 
22 #include "../eth.h"
23 #include "eth_nxp_imx_netc_priv.h"
24 
netc_eth_phylink_callback(const struct device * pdev,struct phy_link_state * state,void * user_data)25 static void netc_eth_phylink_callback(const struct device *pdev, struct phy_link_state *state,
26 				      void *user_data)
27 {
28 	const struct device *dev = (struct device *)user_data;
29 	const struct netc_eth_config *cfg = dev->config;
30 	struct netc_eth_data *data = dev->data;
31 	status_t result;
32 
33 	ARG_UNUSED(pdev);
34 
35 	if (state->is_up) {
36 		LOG_INF("ENETC%d Link up", getSiInstance(cfg->si_idx));
37 		result = EP_Up(&data->handle, PHY_TO_NETC_SPEED(state->speed),
38 			       PHY_TO_NETC_DUPLEX_MODE(state->speed));
39 		if (result != kStatus_Success) {
40 			LOG_ERR("Failed to set MAC up");
41 		}
42 		net_eth_carrier_on(data->iface);
43 	} else {
44 		LOG_INF("ENETC%d Link down", getSiInstance(cfg->si_idx));
45 		result = EP_Down(&data->handle);
46 		if (result != kStatus_Success) {
47 			LOG_ERR("Failed to set MAC down");
48 		}
49 		net_eth_carrier_off(data->iface);
50 	}
51 }
52 
netc_eth_iface_init(struct net_if * iface)53 static void netc_eth_iface_init(struct net_if *iface)
54 {
55 	const struct device *dev = net_if_get_device(iface);
56 	struct netc_eth_data *data = dev->data;
57 	const struct netc_eth_config *cfg = dev->config;
58 	status_t result;
59 
60 	/*
61 	 * For VLAN, this value is only used to get the correct L2 driver.
62 	 * The iface pointer in context should contain the main interface
63 	 * if the VLANs are enabled.
64 	 */
65 	if (data->iface == NULL) {
66 		data->iface = iface;
67 	}
68 
69 	/* Set MAC address */
70 	result = EP_SetPrimaryMacAddr(&data->handle, (uint8_t *)data->mac_addr);
71 	if (result != kStatus_Success) {
72 		LOG_ERR("Failed to set MAC address");
73 	}
74 
75 	net_if_set_link_addr(iface, data->mac_addr, sizeof(data->mac_addr), NET_LINK_ETHERNET);
76 
77 	LOG_INF("ENETC%d MAC: %02x:%02x:%02x:%02x:%02x:%02x", getSiInstance(cfg->si_idx),
78 		data->mac_addr[0], data->mac_addr[1], data->mac_addr[2], data->mac_addr[3],
79 		data->mac_addr[4], data->mac_addr[5]);
80 
81 	ethernet_init(iface);
82 
83 	if (cfg->pseudo_mac) {
84 		return;
85 	}
86 
87 	/*
88 	 * PSI controls the PHY. If PHY is configured either as fixed
89 	 * link or autoneg, the callback is executed at least once
90 	 * immediately after setting it.
91 	 */
92 	if (!device_is_ready(cfg->phy_dev)) {
93 		LOG_ERR("PHY device (%p) is not ready, cannot init iface", cfg->phy_dev);
94 		return;
95 	}
96 	phy_link_callback_set(cfg->phy_dev, &netc_eth_phylink_callback, (void *)dev);
97 
98 	/* Do not start the interface until PHY link is up */
99 	net_if_carrier_off(iface);
100 }
101 
netc_eth_init(const struct device * dev)102 static int netc_eth_init(const struct device *dev)
103 {
104 	const struct netc_eth_config *cfg = dev->config;
105 	int err;
106 
107 	if (cfg->pseudo_mac) {
108 		goto init_common;
109 	}
110 
111 	err = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT);
112 	if (err) {
113 		return err;
114 	}
115 
116 init_common:
117 	return netc_eth_init_common(dev);
118 }
119 
netc_eth_get_phy(const struct device * dev)120 static const struct device *netc_eth_get_phy(const struct device *dev)
121 {
122 	const struct netc_eth_config *cfg = dev->config;
123 
124 	return cfg->phy_dev;
125 }
126 
127 static const struct ethernet_api netc_eth_api = {.iface_api.init = netc_eth_iface_init,
128 						 .get_capabilities = netc_eth_get_capabilities,
129 						 .get_phy = netc_eth_get_phy,
130 						 .set_config = netc_eth_set_config,
131 						 .send = netc_eth_tx};
132 
133 #define NETC_PSI_INSTANCE_DEFINE(n)                                                                \
134 	PINCTRL_DT_INST_DEFINE(n);                                                                 \
135 	NETC_GENERATE_MAC_ADDRESS(n)                                                               \
136 	AT_NONCACHEABLE_SECTION_ALIGN(                                                             \
137 		static uint8_t eth##n##_tx_buff[CONFIG_ETH_NXP_IMX_TX_RING_BUF_SIZE],              \
138 		NETC_BUFF_ALIGN);                                                                  \
139 	AT_NONCACHEABLE_SECTION_ALIGN(                                                             \
140 		static netc_tx_bd_t eth##n##_txbd_array[CONFIG_ETH_NXP_IMX_TX_RING_NUM]            \
141 						       [CONFIG_ETH_NXP_IMX_TX_RING_LEN],           \
142 		NETC_BD_ALIGN);                                                                    \
143 	static netc_tx_frame_info_t eth##n##_txdirty_array[CONFIG_ETH_NXP_IMX_TX_RING_NUM]         \
144 							  [CONFIG_ETH_NXP_IMX_TX_RING_LEN];        \
145 	AT_NONCACHEABLE_SECTION_ALIGN(                                                             \
146 		static rx_buffer_t eth##n##_rx_buff[CONFIG_ETH_NXP_IMX_RX_RING_NUM]                \
147 						   [CONFIG_ETH_NXP_IMX_RX_RING_LEN],               \
148 		NETC_BUFF_ALIGN);                                                                  \
149 	static uint64_t eth##n##_rx_buff_addr_array[CONFIG_ETH_NXP_IMX_RX_RING_NUM]                \
150 						   [CONFIG_ETH_NXP_IMX_RX_RING_LEN];               \
151 	AT_NONCACHEABLE_SECTION(static uint8_t eth##n##_rx_frame[NETC_RX_RING_BUF_SIZE_ALIGN]);    \
152 	AT_NONCACHEABLE_SECTION_ALIGN(                                                             \
153 		static netc_rx_bd_t eth##n##_rxbd_array[CONFIG_ETH_NXP_IMX_RX_RING_NUM]            \
154 						       [CONFIG_ETH_NXP_IMX_RX_RING_LEN],           \
155 		NETC_BD_ALIGN);                                                                    \
156 	static void netc_eth##n##_bdr_init(netc_bdr_config_t *bdr_config,                          \
157 					   netc_rx_bdr_config_t *rx_bdr_config,                    \
158 					   netc_tx_bdr_config_t *tx_bdr_config)                    \
159 	{                                                                                          \
160 		for (uint8_t ring = 0U; ring < CONFIG_ETH_NXP_IMX_RX_RING_NUM; ring++) {           \
161 			for (uint8_t bd = 0U; bd < CONFIG_ETH_NXP_IMX_RX_RING_LEN; bd++) {         \
162 				eth##n##_rx_buff_addr_array[ring][bd] =                            \
163 					(uint64_t)(uintptr_t)&eth##n##_rx_buff[ring][bd];          \
164 			}                                                                          \
165 		}                                                                                  \
166 		memset(bdr_config, 0, sizeof(netc_bdr_config_t));                                  \
167 		memset(rx_bdr_config, 0, sizeof(netc_rx_bdr_config_t));                            \
168 		memset(tx_bdr_config, 0, sizeof(netc_tx_bdr_config_t));                            \
169 		bdr_config->rxBdrConfig = rx_bdr_config;                                           \
170 		bdr_config->txBdrConfig = tx_bdr_config;                                           \
171 		bdr_config->rxBdrConfig[0].bdArray = &eth##n##_rxbd_array[0][0];                   \
172 		bdr_config->rxBdrConfig[0].len = CONFIG_ETH_NXP_IMX_RX_RING_LEN;                   \
173 		bdr_config->rxBdrConfig[0].buffAddrArray = &eth##n##_rx_buff_addr_array[0][0];     \
174 		bdr_config->rxBdrConfig[0].buffSize = NETC_RX_RING_BUF_SIZE_ALIGN;                 \
175 		bdr_config->rxBdrConfig[0].msixEntryIdx = NETC_RX_MSIX_ENTRY_IDX;                  \
176 		bdr_config->rxBdrConfig[0].extendDescEn = false;                                   \
177 		bdr_config->rxBdrConfig[0].enThresIntr = true;                                     \
178 		bdr_config->rxBdrConfig[0].enCoalIntr = true;                                      \
179 		bdr_config->rxBdrConfig[0].intrThreshold = 1;                                      \
180 		bdr_config->txBdrConfig[0].bdArray = &eth##n##_txbd_array[0][0];                   \
181 		bdr_config->txBdrConfig[0].len = CONFIG_ETH_NXP_IMX_TX_RING_LEN;                   \
182 		bdr_config->txBdrConfig[0].dirtyArray = &eth##n##_txdirty_array[0][0];             \
183 		bdr_config->txBdrConfig[0].msixEntryIdx = NETC_TX_MSIX_ENTRY_IDX;                  \
184 		bdr_config->txBdrConfig[0].enIntr = true;                                          \
185 	}                                                                                          \
186 	static struct netc_eth_data netc_eth##n##_data = {                                         \
187 		.mac_addr = DT_INST_PROP_OR(n, local_mac_address, {0}),                            \
188 		.tx_buff = eth##n##_tx_buff,                                                       \
189 		.rx_frame = eth##n##_rx_frame,                                                     \
190 	};                                                                                         \
191 	static const struct netc_eth_config netc_eth##n##_config = {                               \
192 		.generate_mac = netc_eth##n##_generate_mac,                                        \
193 		.bdr_init = netc_eth##n##_bdr_init,                                                \
194 		.phy_dev = (COND_CODE_1(DT_INST_NODE_HAS_PROP(n, phy_handle),                      \
195 					(DEVICE_DT_GET(DT_INST_PHANDLE(n, phy_handle))), NULL)),   \
196 		.phy_mode = NETC_PHY_MODE(DT_DRV_INST(n)),                                         \
197 		.pseudo_mac = DT_ENUM_HAS_VALUE(DT_DRV_INST(n), phy_connection_type, internal),    \
198 		.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),                                       \
199 		.si_idx = (DT_INST_PROP(n, mac_index) << 8) | DT_INST_PROP(n, si_index),           \
200 		.tx_intr_msg_data = NETC_TX_INTR_MSG_DATA_START + n,                               \
201 		.rx_intr_msg_data = NETC_RX_INTR_MSG_DATA_START + n,                               \
202 	};                                                                                         \
203 	ETH_NET_DEVICE_DT_INST_DEFINE(n, netc_eth_init, NULL, &netc_eth##n##_data,                 \
204 				      &netc_eth##n##_config, CONFIG_ETH_INIT_PRIORITY,             \
205 				      &netc_eth_api, NET_ETH_MTU);
206 DT_INST_FOREACH_STATUS_OKAY(NETC_PSI_INSTANCE_DEFINE)
207