stmmac: intel: Add PSE and PCH PTP clock source selection
authorWong, Vee Khee <vee.khee.wong@intel.com>
Wed, 17 Mar 2021 01:32:47 +0000 (09:32 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 19 Mar 2021 02:10:51 +0000 (19:10 -0700)
Intel mGbE variant implemented in EHL and TGL can be set to select
different clock frequency based on GPO bits in MAC_GPIO_STATUS register.

We introduce a new "void (*ptp_clk_freq_config)(void *priv)" in platform
data so that if a platform is required to configure the frequency of clock
source, in this case Intel mGBE does, the platform-specific configuration
of the PTP clock setting is done when stmmac_ptp_register() is called.

Signed-off-by: Wong, Vee Khee <vee.khee.wong@intel.com>
Signed-off-by: Voon Weifeng <weifeng.voon@intel.com>
Co-developed-by: Ong Boon Leong <boon.leong.ong@intel.com>
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
drivers/net/ethernet/stmicro/stmmac/dwmac4.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
include/linux/stmmac.h

index c4964677387122d1f4afb76c1d00ed1e2c832a3b..763b549e3c2d576c422cc538f41d037d7f6b4843 100644 (file)
 #define INTEL_MGBE_ADHOC_ADDR  0x15
 #define INTEL_MGBE_XPCS_ADDR   0x16
 
+/* Selection for PTP Clock Freq belongs to PSE & PCH GbE */
+#define PSE_PTP_CLK_FREQ_MASK          (GMAC_GPO0 | GMAC_GPO3)
+#define PSE_PTP_CLK_FREQ_19_2MHZ       (GMAC_GPO0)
+#define PSE_PTP_CLK_FREQ_200MHZ                (GMAC_GPO0 | GMAC_GPO3)
+#define PSE_PTP_CLK_FREQ_256MHZ                (0)
+#define PCH_PTP_CLK_FREQ_MASK          (GMAC_GPO0)
+#define PCH_PTP_CLK_FREQ_19_2MHZ       (GMAC_GPO0)
+#define PCH_PTP_CLK_FREQ_200MHZ                (0)
+
 struct intel_priv_data {
        int mdio_adhoc_addr;    /* mdio address for serdes & etc */
+       bool is_pse;
 };
 
 /* This struct is used to associate PCI Function of MAC controller on a board,
@@ -204,6 +214,32 @@ static void intel_serdes_powerdown(struct net_device *ndev, void *intel_data)
        }
 }
 
+/* Program PTP Clock Frequency for different variant of
+ * Intel mGBE that has slightly different GPO mapping
+ */
+static void intel_mgbe_ptp_clk_freq_config(void *npriv)
+{
+       struct stmmac_priv *priv = (struct stmmac_priv *)npriv;
+       struct intel_priv_data *intel_priv;
+       u32 gpio_value;
+
+       intel_priv = (struct intel_priv_data *)priv->plat->bsp_priv;
+
+       gpio_value = readl(priv->ioaddr + GMAC_GPIO_STATUS);
+
+       if (intel_priv->is_pse) {
+               /* For PSE GbE, use 200MHz */
+               gpio_value &= ~PSE_PTP_CLK_FREQ_MASK;
+               gpio_value |= PSE_PTP_CLK_FREQ_200MHZ;
+       } else {
+               /* For PCH GbE, use 200MHz */
+               gpio_value &= ~PCH_PTP_CLK_FREQ_MASK;
+               gpio_value |= PCH_PTP_CLK_FREQ_200MHZ;
+       }
+
+       writel(gpio_value, priv->ioaddr + GMAC_GPIO_STATUS);
+}
+
 static void common_default_data(struct plat_stmmacenet_data *plat)
 {
        plat->clk_csr = 2;      /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
@@ -322,6 +358,8 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
                return ret;
        }
 
+       plat->ptp_clk_freq_config = intel_mgbe_ptp_clk_freq_config;
+
        /* Set default value for multicast hash bins */
        plat->multicast_filter_bins = HASH_TABLE_SIZE;
 
@@ -391,8 +429,12 @@ static struct stmmac_pci_info ehl_rgmii1g_info = {
 static int ehl_pse0_common_data(struct pci_dev *pdev,
                                struct plat_stmmacenet_data *plat)
 {
+       struct intel_priv_data *intel_priv = plat->bsp_priv;
+
+       intel_priv->is_pse = true;
        plat->bus_id = 2;
        plat->addr64 = 32;
+
        return ehl_common_data(pdev, plat);
 }
 
@@ -423,8 +465,12 @@ static struct stmmac_pci_info ehl_pse0_sgmii1g_info = {
 static int ehl_pse1_common_data(struct pci_dev *pdev,
                                struct plat_stmmacenet_data *plat)
 {
+       struct intel_priv_data *intel_priv = plat->bsp_priv;
+
+       intel_priv->is_pse = true;
        plat->bus_id = 3;
        plat->addr64 = 32;
+
        return ehl_common_data(pdev, plat);
 }
 
index 82df91c130f780932411d9849312d3dffbd90014..ef8502d2b6e6131d686588c10d356d7991ead520 100644 (file)
@@ -42,6 +42,7 @@
 #define GMAC_HW_FEATURE3               0x00000128
 #define GMAC_MDIO_ADDR                 0x00000200
 #define GMAC_MDIO_DATA                 0x00000204
+#define GMAC_GPIO_STATUS               0x0000020C
 #define GMAC_ARP_ADDR                  0x00000210
 #define GMAC_ADDR_HIGH(reg)            (0x300 + reg * 8)
 #define GMAC_ADDR_LOW(reg)             (0x304 + reg * 8)
@@ -278,6 +279,12 @@ enum power_event {
 #define GMAC_HW_FEAT_DVLAN             BIT(5)
 #define GMAC_HW_FEAT_NRVF              GENMASK(2, 0)
 
+/* GMAC GPIO Status reg */
+#define GMAC_GPO0                      BIT(16)
+#define GMAC_GPO1                      BIT(17)
+#define GMAC_GPO2                      BIT(18)
+#define GMAC_GPO3                      BIT(19)
+
 /* MAC HW ADDR regs */
 #define GMAC_HI_DCS                    GENMASK(18, 16)
 #define GMAC_HI_DCS_SHIFT              16
index 0989e2bb6ee31dece215fdddd5271d1d633d2540..8b10fd10446ff0f7663d2b4b596397ecc6926359 100644 (file)
@@ -192,6 +192,9 @@ void stmmac_ptp_register(struct stmmac_priv *priv)
 {
        int i;
 
+       if (priv->plat->ptp_clk_freq_config)
+               priv->plat->ptp_clk_freq_config(priv);
+
        for (i = 0; i < priv->dma_cap.pps_out_num; i++) {
                if (i >= STMMAC_PPS_MAX)
                        break;
index 51004ebd05401f0b7c447e0f24744baa87433de0..10abc80b601e259581d0ffde6a05b3ec6c13e53f 100644 (file)
@@ -181,6 +181,7 @@ struct plat_stmmacenet_data {
        void (*fix_mac_speed)(void *priv, unsigned int speed);
        int (*serdes_powerup)(struct net_device *ndev, void *priv);
        void (*serdes_powerdown)(struct net_device *ndev, void *priv);
+       void (*ptp_clk_freq_config)(void *priv);
        int (*init)(struct platform_device *pdev, void *priv);
        void (*exit)(struct platform_device *pdev, void *priv);
        struct mac_device_info *(*setup)(void *priv);