Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/stmicro/stmmac/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 7 kB image not shown  

Quelle  dwmac-thead.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * T-HEAD DWMAC platform driver
 *
 * Copyright (C) 2021 Alibaba Group Holding Limited.
 * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org>
 *
 */


#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_net.h>
#include <linux/platform_device.h>

#include "stmmac_platform.h"

#define GMAC_CLK_EN   0x00
#define  GMAC_TX_CLK_EN   BIT(1)
#define  GMAC_TX_CLK_N_EN  BIT(2)
#define  GMAC_TX_CLK_OUT_EN  BIT(3)
#define  GMAC_RX_CLK_EN   BIT(4)
#define  GMAC_RX_CLK_N_EN  BIT(5)
#define  GMAC_EPHY_REF_CLK_EN  BIT(6)
#define GMAC_RXCLK_DELAY_CTRL  0x04
#define  GMAC_RXCLK_BYPASS  BIT(15)
#define  GMAC_RXCLK_INVERT  BIT(14)
#define  GMAC_RXCLK_DELAY  GENMASK(4, 0)
#define GMAC_TXCLK_DELAY_CTRL  0x08
#define  GMAC_TXCLK_BYPASS  BIT(15)
#define  GMAC_TXCLK_INVERT  BIT(14)
#define  GMAC_TXCLK_DELAY  GENMASK(4, 0)
#define GMAC_PLLCLK_DIV   0x0c
#define  GMAC_PLLCLK_DIV_EN  BIT(31)
#define  GMAC_PLLCLK_DIV_NUM  GENMASK(7, 0)
#define GMAC_GTXCLK_SEL   0x18
#define  GMAC_GTXCLK_SEL_PLL  BIT(0)
#define GMAC_INTF_CTRL   0x1c
#define  PHY_INTF_MASK   BIT(0)
#define  PHY_INTF_RGMII   FIELD_PREP(PHY_INTF_MASK, 1)
#define  PHY_INTF_MII_GMII  FIELD_PREP(PHY_INTF_MASK, 0)
#define GMAC_TXCLK_OEN   0x20
#define  TXCLK_DIR_MASK   BIT(0)
#define  TXCLK_DIR_OUTPUT  FIELD_PREP(TXCLK_DIR_MASK, 0)
#define  TXCLK_DIR_INPUT  FIELD_PREP(TXCLK_DIR_MASK, 1)

struct thead_dwmac {
 struct plat_stmmacenet_data *plat;
 void __iomem *apb_base;
 struct device *dev;
};

static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat)
{
 struct thead_dwmac *dwmac = plat->bsp_priv;
 u32 phyif;

 switch (plat->mac_interface) {
 case PHY_INTERFACE_MODE_MII:
  phyif = PHY_INTF_MII_GMII;
  break;
 case PHY_INTERFACE_MODE_RGMII:
 case PHY_INTERFACE_MODE_RGMII_ID:
 case PHY_INTERFACE_MODE_RGMII_TXID:
 case PHY_INTERFACE_MODE_RGMII_RXID:
  phyif = PHY_INTF_RGMII;
  break;
 default:
  dev_err(dwmac->dev, "unsupported phy interface %d\n",
   plat->mac_interface);
  return -EINVAL;
 }

 writel(phyif, dwmac->apb_base + GMAC_INTF_CTRL);
 return 0;
}

static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat)
{
 struct thead_dwmac *dwmac = plat->bsp_priv;
 u32 txclk_dir;

 switch (plat->mac_interface) {
 case PHY_INTERFACE_MODE_MII:
  txclk_dir = TXCLK_DIR_INPUT;
  break;
 case PHY_INTERFACE_MODE_RGMII:
 case PHY_INTERFACE_MODE_RGMII_ID:
 case PHY_INTERFACE_MODE_RGMII_TXID:
 case PHY_INTERFACE_MODE_RGMII_RXID:
  txclk_dir = TXCLK_DIR_OUTPUT;
  break;
 default:
  dev_err(dwmac->dev, "unsupported phy interface %d\n",
   plat->mac_interface);
  return -EINVAL;
 }

 writel(txclk_dir, dwmac->apb_base + GMAC_TXCLK_OEN);
 return 0;
}

static int thead_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i,
     phy_interface_t interface, int speed)
{
 struct thead_dwmac *dwmac = bsp_priv;
 struct plat_stmmacenet_data *plat;
 unsigned long rate;
 long tx_rate;
 u32 div, reg;

 plat = dwmac->plat;

 switch (plat->mac_interface) {
 /* For MII, rxc/txc is provided by phy */
 case PHY_INTERFACE_MODE_MII:
  return 0;

 case PHY_INTERFACE_MODE_RGMII:
 case PHY_INTERFACE_MODE_RGMII_ID:
 case PHY_INTERFACE_MODE_RGMII_RXID:
 case PHY_INTERFACE_MODE_RGMII_TXID:
  rate = clk_get_rate(plat->stmmac_clk);

  writel(0, dwmac->apb_base + GMAC_PLLCLK_DIV);

  tx_rate = rgmii_clock(speed);
  if (tx_rate < 0) {
   dev_err(dwmac->dev, "invalid speed %d\n", speed);
   return tx_rate;
  }

  div = rate / tx_rate;
  if (rate != tx_rate * div) {
   dev_err(dwmac->dev, "invalid gmac rate %lu\n", rate);
   return -EINVAL;
  }

  reg = FIELD_PREP(GMAC_PLLCLK_DIV_EN, 1) |
        FIELD_PREP(GMAC_PLLCLK_DIV_NUM, div);
  writel(reg, dwmac->apb_base + GMAC_PLLCLK_DIV);
  return 0;

 default:
  dev_err(dwmac->dev, "unsupported phy interface %d\n",
   plat->mac_interface);
  return -EINVAL;
 }
}

static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat)
{
 struct thead_dwmac *dwmac = plat->bsp_priv;
 u32 reg, div;

 switch (plat->mac_interface) {
 case PHY_INTERFACE_MODE_MII:
  reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN;
  break;

 case PHY_INTERFACE_MODE_RGMII:
 case PHY_INTERFACE_MODE_RGMII_ID:
 case PHY_INTERFACE_MODE_RGMII_RXID:
 case PHY_INTERFACE_MODE_RGMII_TXID:
  /* use pll */
  div = clk_get_rate(plat->stmmac_clk) / rgmii_clock(SPEED_1000);
  reg = FIELD_PREP(GMAC_PLLCLK_DIV_EN, 1) |
        FIELD_PREP(GMAC_PLLCLK_DIV_NUM, div);

  writel(0, dwmac->apb_base + GMAC_PLLCLK_DIV);
  writel(reg, dwmac->apb_base + GMAC_PLLCLK_DIV);

  writel(GMAC_GTXCLK_SEL_PLL, dwmac->apb_base + GMAC_GTXCLK_SEL);
  reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN |
        GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN;
  break;

 default:
  dev_err(dwmac->dev, "unsupported phy interface %d\n",
   plat->mac_interface);
  return -EINVAL;
 }

 writel(reg, dwmac->apb_base + GMAC_CLK_EN);
 return 0;
}

static int thead_dwmac_init(struct platform_device *pdev, void *priv)
{
 struct thead_dwmac *dwmac = priv;
 unsigned int reg;
 int ret;

 ret = thead_dwmac_set_phy_if(dwmac->plat);
 if (ret)
  return ret;

 ret = thead_dwmac_set_txclk_dir(dwmac->plat);
 if (ret)
  return ret;

 reg = readl(dwmac->apb_base + GMAC_RXCLK_DELAY_CTRL);
 reg &= ~(GMAC_RXCLK_DELAY);
 reg |= FIELD_PREP(GMAC_RXCLK_DELAY, 0);
 writel(reg, dwmac->apb_base + GMAC_RXCLK_DELAY_CTRL);

 reg = readl(dwmac->apb_base + GMAC_TXCLK_DELAY_CTRL);
 reg &= ~(GMAC_TXCLK_DELAY);
 reg |= FIELD_PREP(GMAC_TXCLK_DELAY, 0);
 writel(reg, dwmac->apb_base + GMAC_TXCLK_DELAY_CTRL);

 return thead_dwmac_enable_clk(dwmac->plat);
}

static int thead_dwmac_probe(struct platform_device *pdev)
{
 struct stmmac_resources stmmac_res;
 struct plat_stmmacenet_data *plat;
 struct thead_dwmac *dwmac;
 struct clk *apb_clk;
 void __iomem *apb;
 int ret;

 ret = stmmac_get_platform_resources(pdev, &stmmac_res);
 if (ret)
  return dev_err_probe(&pdev->dev, ret,
         "failed to get resources\n");

 plat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
 if (IS_ERR(plat))
  return dev_err_probe(&pdev->dev, PTR_ERR(plat),
         "dt configuration failed\n");

 /*
 * The APB clock is essential for accessing glue registers. However,
 * old devicetrees don't describe it correctly. We continue to probe
 * and emit a warning if it isn't present.
 */

 apb_clk = devm_clk_get_enabled(&pdev->dev, "apb");
 if (PTR_ERR(apb_clk) == -ENOENT)
  dev_warn(&pdev->dev,
    "cannot get apb clock, link may break after speed changes\n");
 else if (IS_ERR(apb_clk))
  return dev_err_probe(&pdev->dev, PTR_ERR(apb_clk),
         "failed to get apb clock\n");

 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
 if (!dwmac)
  return -ENOMEM;

 apb = devm_platform_ioremap_resource(pdev, 1);
 if (IS_ERR(apb))
  return dev_err_probe(&pdev->dev, PTR_ERR(apb),
         "failed to remap gmac apb registers\n");

 dwmac->dev = &pdev->dev;
 dwmac->plat = plat;
 dwmac->apb_base = apb;
 plat->bsp_priv = dwmac;
 plat->set_clk_tx_rate = thead_set_clk_tx_rate;
 plat->init = thead_dwmac_init;

 return devm_stmmac_pltfr_probe(pdev, plat, &stmmac_res);
}

static const struct of_device_id thead_dwmac_match[] = {
 { .compatible = "thead,th1520-gmac" },
 { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, thead_dwmac_match);

static struct platform_driver thead_dwmac_driver = {
 .probe = thead_dwmac_probe,
 .driver = {
  .name = "thead-dwmac",
  .pm = &stmmac_pltfr_pm_ops,
  .of_match_table = thead_dwmac_match,
 },
};
module_platform_driver(thead_dwmac_driver);

MODULE_AUTHOR("Jisheng Zhang ");
MODULE_AUTHOR("Drew Fustini ");
MODULE_DESCRIPTION("T-HEAD DWMAC platform driver");
MODULE_LICENSE("GPL");

Messung V0.5
C=96 H=87 G=91

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.