[PATCH 02/19] net: airoha: add initial support for multiple GDM port
Mikhail Kshevetskiy
mikhail.kshevetskiy at iopsys.eu
Thu Dec 4 05:14:16 CET 2025
From: Christian Marangi <ansuelsmth at gmail.com>
Rework the driver to support multiple GDM port. The driver is split to
main driver as a MISC driver with forced probe (by using the
DM_FLAG_PROBE_AFTER_BIND) and each GDM port register a ETH driver.
This permit a 1:1 implementation with the linux kernel driver and permit
to use the same exact DT nodes.
Signed-off-by: Christian Marangi <ansuelsmth at gmail.com>
---
drivers/net/airoha_eth.c | 156 ++++++++++++++++++++++++++++++++++-----
1 file changed, 136 insertions(+), 20 deletions(-)
diff --git a/drivers/net/airoha_eth.c b/drivers/net/airoha_eth.c
index 3234d875887..31937137d59 100644
--- a/drivers/net/airoha_eth.c
+++ b/drivers/net/airoha_eth.c
@@ -9,6 +9,7 @@
*/
#include <dm.h>
+#include <dm/device-internal.h>
#include <dm/devres.h>
#include <mapmem.h>
#include <net.h>
@@ -23,7 +24,7 @@
#include <linux/time.h>
#include <asm/arch/scu-regmap.h>
-#define AIROHA_MAX_NUM_GDM_PORTS 1
+#define AIROHA_MAX_NUM_GDM_PORTS 4
#define AIROHA_MAX_NUM_QDMA 1
#define AIROHA_MAX_NUM_RSTS 3
#define AIROHA_MAX_NUM_XSI_RSTS 4
@@ -37,6 +38,8 @@
#define TX_DSCP_NUM 16
#define RX_DSCP_NUM PKTBUFSRX
+#define AIROHA_GDM_PORT_STRING_LEN sizeof("airoha-gdmX")
+
/* SCU */
#define SCU_SHARE_FEMEM_SEL 0x958
@@ -245,6 +248,21 @@
#define QDMA_ETH_RXMSG_CRSN_MASK GENMASK(20, 16)
#define QDMA_ETH_RXMSG_PPE_ENTRY_MASK GENMASK(15, 0)
+enum {
+ FE_PSE_PORT_CDM1,
+ FE_PSE_PORT_GDM1,
+ FE_PSE_PORT_GDM2,
+ FE_PSE_PORT_GDM3,
+ FE_PSE_PORT_PPE1,
+ FE_PSE_PORT_CDM2,
+ FE_PSE_PORT_CDM3,
+ FE_PSE_PORT_CDM4,
+ FE_PSE_PORT_PPE2,
+ FE_PSE_PORT_GDM4,
+ FE_PSE_PORT_CDM5,
+ FE_PSE_PORT_DROP = 0xf,
+};
+
struct airoha_qdma_desc {
__le32 rsv;
__le32 ctrl;
@@ -309,11 +327,14 @@ struct airoha_eth {
struct reset_ctl_bulk rsts;
struct reset_ctl_bulk xsi_rsts;
+ struct airoha_eth_soc_data *soc;
+
struct airoha_qdma qdma[AIROHA_MAX_NUM_QDMA];
- struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
+ char gdm_port_str[AIROHA_MAX_NUM_GDM_PORTS][AIROHA_GDM_PORT_STRING_LEN];
};
struct airoha_eth_soc_data {
+ u32 version;
int num_xsi_rsts;
const char * const *xsi_rsts_names;
const char *switch_compatible;
@@ -375,6 +396,8 @@ static u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val)
#define airoha_switch_wr(eth, offset, val) \
airoha_wr((eth)->switch_regs, (offset), (val))
+static struct driver airoha_eth_port;
+
static inline dma_addr_t dma_map_unaligned(void *vaddr, size_t len,
enum dma_data_direction dir)
{
@@ -396,11 +419,26 @@ static inline void dma_unmap_unaligned(dma_addr_t addr, size_t len,
dma_unmap_single(start, end - start, dir);
}
+static int airoha_get_fe_port(struct airoha_gdm_port *port)
+{
+ struct airoha_qdma *qdma = port->qdma;
+ struct airoha_eth *eth = qdma->eth;
+
+ switch (eth->soc->version) {
+ case 0x7523:
+ /* FIXME: GDM1 is the only supported port */
+ return FE_PSE_PORT_GDM1;
+ case 0x7581:
+ default:
+ return port->id == 4 ? FE_PSE_PORT_GDM4 : port->id;
+ }
+}
+
static void airoha_fe_maccr_init(struct airoha_eth *eth)
{
int p;
- for (p = 1; p <= ARRAY_SIZE(eth->ports); p++) {
+ for (p = 1; p <= AIROHA_MAX_NUM_GDM_PORTS; p++) {
/*
* Disable any kind of CRC drop or offload.
* Enable padding of short TX packets to 60 bytes.
@@ -738,11 +776,35 @@ static int airoha_switch_init(struct udevice *dev, struct airoha_eth *eth)
return 0;
}
+static int airoha_alloc_gdm_port(struct udevice *dev, ofnode node)
+{
+ struct airoha_eth *eth = dev_get_priv(dev);
+ struct udevice *gdm_dev;
+ char *str;
+ int ret;
+ u32 id;
+
+ ret = ofnode_read_u32(node, "reg", &id);
+ if (ret)
+ return ret;
+
+ if (id > AIROHA_MAX_NUM_GDM_PORTS)
+ return -EINVAL;
+
+ str = eth->gdm_port_str[id];
+ snprintf(str, AIROHA_GDM_PORT_STRING_LEN,
+ "airoha-gdm%d", id);
+
+ return device_bind_with_driver_data(dev, &airoha_eth_port, str,
+ (ulong)eth, node, &gdm_dev);
+}
+
static int airoha_eth_probe(struct udevice *dev)
{
struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
struct airoha_eth *eth = dev_get_priv(dev);
struct regmap *scu_regmap;
+ ofnode node;
int i, ret;
scu_regmap = airoha_get_scu_regmap();
@@ -755,6 +817,8 @@ static int airoha_eth_probe(struct udevice *dev)
*/
regmap_write(scu_regmap, SCU_SHARE_FEMEM_SEL, 0x0);
+ eth->soc = data;
+
eth->fe_regs = dev_remap_addr_name(dev, "fe");
if (!eth->fe_regs)
return -ENOMEM;
@@ -794,13 +858,42 @@ static int airoha_eth_probe(struct udevice *dev)
if (ret)
return ret;
+ ofnode_for_each_subnode(node, dev_ofnode(dev)) {
+ if (!ofnode_device_is_compatible(node, "airoha,eth-mac"))
+ continue;
+
+ if (!ofnode_is_enabled(node))
+ continue;
+
+ ret = airoha_alloc_gdm_port(dev, node);
+ if (ret)
+ return ret;
+ }
+
return airoha_switch_init(dev, eth);
}
+static int airoha_eth_port_of_to_plat(struct udevice *dev)
+{
+ struct airoha_gdm_port *port = dev_get_priv(dev);
+
+ return dev_read_u32(dev, "reg", &port->id);
+}
+
+static int airoha_eth_port_probe(struct udevice *dev)
+{
+ struct airoha_eth *eth = (void *)dev_get_driver_data(dev);
+ struct airoha_gdm_port *port = dev_get_priv(dev);
+
+ port->qdma = ð->qdma[0];
+
+ return 0;
+}
+
static int airoha_eth_init(struct udevice *dev)
{
- struct airoha_eth *eth = dev_get_priv(dev);
- struct airoha_qdma *qdma = ð->qdma[0];
+ struct airoha_gdm_port *port = dev_get_priv(dev);
+ struct airoha_qdma *qdma = port->qdma;
struct airoha_queue *q;
int qid;
@@ -818,8 +911,8 @@ static int airoha_eth_init(struct udevice *dev)
static void airoha_eth_stop(struct udevice *dev)
{
- struct airoha_eth *eth = dev_get_priv(dev);
- struct airoha_qdma *qdma = ð->qdma[0];
+ struct airoha_gdm_port *port = dev_get_priv(dev);
+ struct airoha_qdma *qdma = port->qdma;
airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG,
GLOBAL_CFG_TX_DMA_EN_MASK |
@@ -828,8 +921,8 @@ static void airoha_eth_stop(struct udevice *dev)
static int airoha_eth_send(struct udevice *dev, void *packet, int length)
{
- struct airoha_eth *eth = dev_get_priv(dev);
- struct airoha_qdma *qdma = ð->qdma[0];
+ struct airoha_gdm_port *port = dev_get_priv(dev);
+ struct airoha_qdma *qdma = port->qdma;
struct airoha_qdma_desc *desc;
struct airoha_queue *q;
dma_addr_t dma_addr;
@@ -851,7 +944,7 @@ static int airoha_eth_send(struct udevice *dev, void *packet, int length)
desc = &q->desc[q->head];
index = (q->head + 1) % q->ndesc;
- fport = 1;
+ fport = airoha_get_fe_port(port);
msg0 = 0;
msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) |
@@ -893,8 +986,8 @@ static int airoha_eth_send(struct udevice *dev, void *packet, int length)
static int airoha_eth_recv(struct udevice *dev, int flags, uchar **packetp)
{
- struct airoha_eth *eth = dev_get_priv(dev);
- struct airoha_qdma *qdma = ð->qdma[0];
+ struct airoha_gdm_port *port = dev_get_priv(dev);
+ struct airoha_qdma *qdma = port->qdma;
struct airoha_qdma_desc *desc;
struct airoha_queue *q;
u16 length;
@@ -921,8 +1014,8 @@ static int airoha_eth_recv(struct udevice *dev, int flags, uchar **packetp)
static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
{
- struct airoha_eth *eth = dev_get_priv(dev);
- struct airoha_qdma *qdma = ð->qdma[0];
+ struct airoha_gdm_port *port = dev_get_priv(dev);
+ struct airoha_qdma *qdma = port->qdma;
struct airoha_queue *q;
int qid;
@@ -963,8 +1056,9 @@ static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
static int arht_eth_write_hwaddr(struct udevice *dev)
{
+ struct airoha_gdm_port *port = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_plat(dev);
- struct airoha_eth *eth = dev_get_priv(dev);
+ struct airoha_qdma *qdma = port->qdma;
unsigned char *mac = pdata->enetaddr;
u32 macaddr_lsb, macaddr_msb;
@@ -976,19 +1070,32 @@ static int arht_eth_write_hwaddr(struct udevice *dev)
FIELD_PREP(SMACCR1_MAC0, mac[0]);
/* Set MAC for Switch */
- airoha_switch_wr(eth, SWITCH_SMACCR0, macaddr_lsb);
- airoha_switch_wr(eth, SWITCH_SMACCR1, macaddr_msb);
+ airoha_switch_wr(qdma->eth, SWITCH_SMACCR0, macaddr_lsb);
+ airoha_switch_wr(qdma->eth, SWITCH_SMACCR1, macaddr_msb);
+
+ return 0;
+}
+
+static int airoha_eth_bind(struct udevice *dev)
+{
+ /*
+ * Force Probe as we set the Main ETH driver as misc
+ * to register multiple eth port for each GDM
+ */
+ dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
return 0;
}
static const struct airoha_eth_soc_data en7523_data = {
+ .version = 0x7523,
.xsi_rsts_names = en7523_xsi_rsts_names,
.num_xsi_rsts = ARRAY_SIZE(en7523_xsi_rsts_names),
.switch_compatible = "airoha,en7523-switch",
};
static const struct airoha_eth_soc_data en7581_data = {
+ .version = 0x7581,
.xsi_rsts_names = en7581_xsi_rsts_names,
.num_xsi_rsts = ARRAY_SIZE(en7581_xsi_rsts_names),
.switch_compatible = "airoha,en7581-switch",
@@ -1013,12 +1120,21 @@ static const struct eth_ops airoha_eth_ops = {
.write_hwaddr = arht_eth_write_hwaddr,
};
+static struct driver airoha_eth_port = {
+ .name = "airoha-eth-port",
+ .id = UCLASS_ETH,
+ .of_to_plat = airoha_eth_port_of_to_plat,
+ .probe = airoha_eth_port_probe,
+ .ops = &airoha_eth_ops,
+ .priv_auto = sizeof(struct airoha_gdm_port),
+ .plat_auto = sizeof(struct eth_pdata),
+};
+
U_BOOT_DRIVER(airoha_eth) = {
.name = "airoha-eth",
- .id = UCLASS_ETH,
+ .id = UCLASS_MISC,
.of_match = airoha_eth_ids,
.probe = airoha_eth_probe,
- .ops = &airoha_eth_ops,
+ .bind = airoha_eth_bind,
.priv_auto = sizeof(struct airoha_eth),
- .plat_auto = sizeof(struct eth_pdata),
};
--
2.51.0
More information about the U-Boot
mailing list