From: Christian Marangi <[email protected]> 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 <[email protected]> --- 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

