// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2023, Intel Corporation */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dwc_eth_xgmac.h" #define SOCFPGA_XGMAC_SYSCON_ARG_COUNT 2 static int dwxgmac_socfpga_do_setphy(struct udevice *dev, u32 modereg) { struct xgmac_priv *xgmac = dev_get_priv(dev); int ret; u32 modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << xgmac->syscon_phy_regshift; if (!(IS_ENABLED(CONFIG_SPL_BUILD)) && IS_ENABLED(CONFIG_SPL_ATF)) { u32 index = ((u64)xgmac->syscon_phy - socfpga_get_sysmgr_addr() - SYSMGR_SOC64_EMAC0) >> 2; u32 id = SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC0 + index; ret = socfpga_secure_reg_update32(id, modemask, modereg << xgmac->syscon_phy_regshift); if (ret) { dev_err(dev, "Failed to set PHY register via SMC call\n"); return ret; } } else { clrsetbits_le32(xgmac->phy, modemask, modereg); } return 0; } static int xgmac_probe_resources_socfpga(struct udevice *dev) { struct xgmac_priv *xgmac = dev_get_priv(dev); struct regmap *reg_map; struct ofnode_phandle_args args; void *range; phy_interface_t interface; int ret; u32 modereg; interface = xgmac->config->interface(dev); switch (interface) { case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_GMII: modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; break; case PHY_INTERFACE_MODE_RMII: modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII; break; case PHY_INTERFACE_MODE_RGMII: modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; break; default: dev_err(dev, "Unsupported PHY mode\n"); return -EINVAL; } /* Get PHY syscon */ ret = dev_read_phandle_with_args(dev, "altr,sysmgr-syscon", NULL, SOCFPGA_XGMAC_SYSCON_ARG_COUNT, 0, &args); if (ret) { dev_err(dev, "Failed to get syscon: %d\n", ret); return ret; } if (args.args_count != SOCFPGA_XGMAC_SYSCON_ARG_COUNT) { dev_err(dev, "Invalid number of syscon args\n"); return -EINVAL; } reg_map = syscon_node_to_regmap(args.node); if (IS_ERR(reg_map)) { ret = PTR_ERR(reg_map); dev_err(dev, "Failed to get reg_map: %d\n", ret); return ret; } range = regmap_get_range(reg_map, 0); if (!range) { dev_err(dev, "Failed to get reg_map: %d\n", ret); return -ENOMEM; } xgmac->syscon_phy = range + args.args[0]; xgmac->syscon_phy_regshift = args.args[1]; /* Get Reset Bulk */ ret = reset_get_bulk(dev, &xgmac->reset_bulk); if (ret) { dev_err(dev, "Failed to get reset: %d\n", ret); return ret; } ret = reset_assert_bulk(&xgmac->reset_bulk); if (ret) { dev_err(dev, "XGMAC failed to assert reset: %d\n", ret); return ret; } ret = dwxgmac_socfpga_do_setphy(dev, modereg); if (ret) return ret; ret = reset_deassert_bulk(&xgmac->reset_bulk); if (ret) { dev_err(dev, "XGMAC failed to de-assert reset: %d\n", ret); return ret; } ret = clk_get_by_name(dev, "stmmaceth", &xgmac->clk_common); if (ret) { pr_err("clk_get_by_name(stmmaceth) failed: %d", ret); goto err_probe; } return 0; err_probe: debug("%s: returns %d\n", __func__, ret); return ret; } static int xgmac_get_enetaddr_socfpga(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); struct xgmac_priv *xgmac = dev_get_priv(dev); u32 hi_addr, lo_addr; debug("%s(dev=%p):\n", __func__, dev); /* Read the MAC Address from the hardawre */ hi_addr = readl(&xgmac->mac_regs->address0_high); lo_addr = readl(&xgmac->mac_regs->address0_low); pdata->enetaddr[0] = lo_addr & 0xff; pdata->enetaddr[1] = (lo_addr >> 8) & 0xff; pdata->enetaddr[2] = (lo_addr >> 16) & 0xff; pdata->enetaddr[3] = (lo_addr >> 24) & 0xff; pdata->enetaddr[4] = hi_addr & 0xff; pdata->enetaddr[5] = (hi_addr >> 8) & 0xff; return !is_valid_ethaddr(pdata->enetaddr); } static int xgmac_start_resets_socfpga(struct udevice *dev) { struct xgmac_priv *xgmac = dev_get_priv(dev); int ret; debug("%s(dev=%p):\n", __func__, dev); ret = reset_assert_bulk(&xgmac->reset_bulk); if (ret < 0) { pr_err("xgmac reset assert failed: %d", ret); return ret; } udelay(2); ret = reset_deassert_bulk(&xgmac->reset_bulk); if (ret < 0) { pr_err("xgmac reset de-assert failed: %d", ret); return ret; } return 0; } static struct xgmac_ops xgmac_socfpga_ops = { .xgmac_inval_desc = xgmac_inval_desc_generic, .xgmac_flush_desc = xgmac_flush_desc_generic, .xgmac_inval_buffer = xgmac_inval_buffer_generic, .xgmac_flush_buffer = xgmac_flush_buffer_generic, .xgmac_probe_resources = xgmac_probe_resources_socfpga, .xgmac_remove_resources = xgmac_null_ops, .xgmac_stop_resets = xgmac_null_ops, .xgmac_start_resets = xgmac_start_resets_socfpga, .xgmac_stop_clks = xgmac_null_ops, .xgmac_start_clks = xgmac_null_ops, .xgmac_calibrate_pads = xgmac_null_ops, .xgmac_disable_calibration = xgmac_null_ops, .xgmac_get_enetaddr = xgmac_get_enetaddr_socfpga, }; struct xgmac_config __maybe_unused xgmac_socfpga_config = { .reg_access_always_ok = false, .swr_wait = 50, .config_mac = XGMAC_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, .config_mac_mdio = XGMAC_MAC_MDIO_ADDRESS_CR_350_400, .axi_bus_width = XGMAC_AXI_WIDTH_64, .interface = dev_read_phy_mode, .ops = &xgmac_socfpga_ops };