Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

144 lines
5.3 KiB

/*
* Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(dsa_netc, CONFIG_ETHERNET_LOG_LEVEL);
#include <zephyr/net/ethernet.h>
#include <zephyr/drivers/pinctrl.h>
#include "../eth.h"
#include "nxp_imx_netc.h"
#include "fsl_netc_switch.h"
#define DT_DRV_COMPAT nxp_netc_switch
#define PRV_DATA(ctx) ((struct dsa_netc_data *const)(ctx)->prv_data)
struct dsa_netc_port_config {
const struct pinctrl_dev_config *pincfg;
netc_hw_mii_mode_t phy_mode;
};
struct dsa_netc_data {
swt_config_t swt_config;
swt_handle_t swt_handle;
netc_cmd_bd_t *cmd_bd;
};
static int dsa_netc_port_init(const struct device *dev)
{
const struct dsa_port_config *cfg = dev->config;
struct dsa_netc_port_config *prv_cfg = cfg->prv_config;
struct dsa_switch_context *dsa_switch_ctx = dev->data;
struct dsa_netc_data *prv = PRV_DATA(dsa_switch_ctx);
swt_config_t *swt_config = &prv->swt_config;
int ret;
if (prv_cfg->pincfg != NULL) {
ret = pinctrl_apply_state(prv_cfg->pincfg, PINCTRL_STATE_DEFAULT);
if (ret < 0) {
return ret;
}
}
/* Get default config when beginning to init the first port */
if (dsa_switch_ctx->init_ports == 1) {
SWT_GetDefaultConfig(swt_config);
swt_config->bridgeCfg.dVFCfg.portMembership = 0x0;
}
/* miiSpeed and miiDuplex will get set correctly when link is up */
swt_config->ports[cfg->port_idx].ethMac.miiMode = prv_cfg->phy_mode;
swt_config->bridgeCfg.dVFCfg.portMembership |= (1 << cfg->port_idx);
swt_config->ports[cfg->port_idx].bridgeCfg.enMacStationMove = true;
return 0;
}
static void dsa_netc_port_generate_random_mac(uint8_t *mac_addr)
{
gen_random_mac(mac_addr, FREESCALE_OUI_B0, FREESCALE_OUI_B1, FREESCALE_OUI_B2);
}
static int dsa_netc_switch_setup(const struct dsa_switch_context *dsa_switch_ctx)
{
struct dsa_netc_data *prv = PRV_DATA(dsa_switch_ctx);
swt_config_t *swt_config = &prv->swt_config;
status_t result;
swt_config->cmdRingUse = 1U;
swt_config->cmdBdrCfg[0].bdBase = prv->cmd_bd;
swt_config->cmdBdrCfg[0].bdLength = 8U;
result = SWT_Init(&prv->swt_handle, &prv->swt_config);
if (result != kStatus_Success) {
return -EIO;
}
return 0;
}
static void dsa_netc_port_phylink_change(const struct device *phydev, struct phy_link_state *state,
void *user_data)
{
const struct device *dev = (struct device *)user_data;
struct net_if *iface = net_if_lookup_by_dev(dev);
const struct dsa_port_config *cfg = dev->config;
struct dsa_switch_context *dsa_switch_ctx = dev->data;
struct dsa_netc_data *prv = PRV_DATA(dsa_switch_ctx);
status_t result;
if (state->is_up) {
LOG_INF("DSA user port %d Link up", cfg->port_idx);
result = SWT_SetEthPortMII(&prv->swt_handle, cfg->port_idx,
PHY_TO_NETC_SPEED(state->speed),
PHY_TO_NETC_DUPLEX_MODE(state->speed));
if (result != kStatus_Success) {
LOG_ERR("DSA user port %d failed to set MAC up", cfg->port_idx);
}
net_eth_carrier_on(iface);
} else {
LOG_INF("DSA user port %d Link down", cfg->port_idx);
net_eth_carrier_off(iface);
}
}
static struct dsa_api dsa_netc_api = {
.port_init = dsa_netc_port_init,
.port_generate_random_mac = dsa_netc_port_generate_random_mac,
.switch_setup = dsa_netc_switch_setup,
.port_phylink_change = dsa_netc_port_phylink_change,
};
#define DSA_NETC_PORT_INST_INIT(port, n) \
COND_CODE_1(DT_NUM_PINCTRL_STATES(port), \
(PINCTRL_DT_DEFINE(port);), (EMPTY)) \
struct dsa_netc_port_config dsa_netc_##n##_##port##_config = { \
.pincfg = COND_CODE_1(DT_NUM_PINCTRL_STATES(port), \
(PINCTRL_DT_DEV_CONFIG_GET(port)), NULL), \
.phy_mode = NETC_PHY_MODE(port), \
}; \
struct dsa_port_config dsa_##n##_##port##_config = { \
.use_random_mac_addr = DT_NODE_HAS_PROP(port, zephyr_random_mac_address), \
.mac_addr = DT_PROP_OR(port, local_mac_address, {0}), \
.port_idx = DT_REG_ADDR(port), \
.phy_dev = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(port, phy_handle)), \
.phy_mode = DT_PROP_OR(port, phy_connection_type, ""), \
.ethernet_connection = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(port, ethernet)), \
.prv_config = &dsa_netc_##n##_##port##_config, \
}; \
DSA_PORT_INST_INIT(port, n, &dsa_##n##_##port##_config)
#define DSA_NETC_DEVICE(n) \
AT_NONCACHEABLE_SECTION_ALIGN(static netc_cmd_bd_t dsa_netc_##n##_cmd_bd[8], \
NETC_BD_ALIGN); \
static struct dsa_netc_data dsa_netc_data_##n = { \
.cmd_bd = dsa_netc_##n##_cmd_bd, \
}; \
DSA_SWITCH_INST_INIT(n, &dsa_netc_api, &dsa_netc_data_##n, DSA_NETC_PORT_INST_INIT);
DT_INST_FOREACH_STATUS_OKAY(DSA_NETC_DEVICE);