cregit-Linux how code gets into the kernel

Release 4.11 drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c

/*
 * dwmac-sti.c - STMicroelectronics DWMAC Specific Glue layer
 *
 * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
 * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
 * Contributors: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/stmmac.h>
#include <linux/phy.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_net.h>

#include "stmmac_platform.h"


#define DWMAC_125MHZ	125000000

#define DWMAC_50MHZ	50000000

#define DWMAC_25MHZ	25000000

#define DWMAC_2_5MHZ	2500000


#define IS_PHY_IF_MODE_RGMII(iface)	(iface == PHY_INTERFACE_MODE_RGMII || \
                        iface == PHY_INTERFACE_MODE_RGMII_ID || \
                        iface == PHY_INTERFACE_MODE_RGMII_RXID || \
                        iface == PHY_INTERFACE_MODE_RGMII_TXID)


#define IS_PHY_IF_MODE_GBIT(iface)	(IS_PHY_IF_MODE_RGMII(iface) || \
                                         iface == PHY_INTERFACE_MODE_GMII)

/* STiH4xx register definitions (STiH415/STiH416/STiH407/STiH410 families)
 *
 * Below table summarizes the clock requirement and clock sources for
 * supported phy interface modes with link speeds.
 * ________________________________________________
 *|  PHY_MODE   | 1000 Mbit Link | 100 Mbit Link   |
 * ------------------------------------------------
 *|     MII     |       n/a      |      25Mhz      |
 *|             |                |      txclk      |
 * ------------------------------------------------
 *|     GMII    |     125Mhz     |      25Mhz      |
 *|             |  clk-125/txclk |      txclk      |
 * ------------------------------------------------
 *|     RGMII   |     125Mhz     |      25Mhz      |
 *|             |  clk-125/txclk |      clkgen     |
 *|             |    clkgen      |                 |
 * ------------------------------------------------
 *|     RMII    |       n/a      |      25Mhz      |
 *|             |                |clkgen/phyclk-in |
 * ------------------------------------------------
 *
 *        Register Configuration
 *-------------------------------
 * src   |BIT(8)| BIT(7)| BIT(6)|
 *-------------------------------
 * txclk |   0  |  n/a  |   1   |
 *-------------------------------
 * ck_125|   0  |  n/a  |   0   |
 *-------------------------------
 * phyclk|   1  |   0   |  n/a  |
 *-------------------------------
 * clkgen|   1  |   1   |  n/a  |
 *-------------------------------
 */


#define STIH4XX_RETIME_SRC_MASK			GENMASK(8, 6)

#define STIH4XX_ETH_SEL_TX_RETIME_CLK		BIT(8)

#define STIH4XX_ETH_SEL_INTERNAL_NOTEXT_PHYCLK	BIT(7)

#define STIH4XX_ETH_SEL_TXCLK_NOT_CLK125	BIT(6)

/* STiD127 register definitions
 *-----------------------
 * src   |BIT(6)| BIT(7)|
 *-----------------------
 * MII   |  1   |   n/a |
 *-----------------------
 * RMII  |  n/a |   1   |
 * clkgen|      |       |
 *-----------------------
 * RMII  |  n/a |   0   |
 * phyclk|      |       |
 *-----------------------
 * RGMII |  1   |  n/a  |
 * clkgen|      |       |
 *-----------------------
 */


#define STID127_RETIME_SRC_MASK			GENMASK(7, 6)

#define STID127_ETH_SEL_INTERNAL_NOTEXT_PHYCLK	BIT(7)

#define STID127_ETH_SEL_INTERNAL_NOTEXT_TXCLK	BIT(6)


#define ENMII_MASK	GENMASK(5, 5)

#define ENMII		BIT(5)

#define EN_MASK		GENMASK(1, 1)

#define EN		BIT(1)

/*
 * 3 bits [4:2]
 *      000-GMII/MII
 *      001-RGMII
 *      010-SGMII
 *      100-RMII
 */

#define MII_PHY_SEL_MASK	GENMASK(4, 2)

#define ETH_PHY_SEL_RMII	BIT(4)

#define ETH_PHY_SEL_SGMII	BIT(3)

#define ETH_PHY_SEL_RGMII	BIT(2)

#define ETH_PHY_SEL_GMII	0x0

#define ETH_PHY_SEL_MII		0x0


struct sti_dwmac {
	
int interface;		/* MII interface */
	
bool ext_phyclk;	/* Clock from external PHY */
	
u32 tx_retime_src;	/* TXCLK Retiming*/
	
struct clk *clk;	/* PHY clock */
	
u32 ctrl_reg;		/* GMAC glue-logic control register */
	
int clk_sel_reg;	/* GMAC ext clk selection register */
	
struct regmap *regmap;
	
bool gmac_en;
	
u32 speed;
	
void (*fix_retime_src)(void *priv, unsigned int speed);
};


struct sti_dwmac_of_data {
	
void (*fix_retime_src)(void *priv, unsigned int speed);
};


static u32 phy_intf_sels[] = {
	[PHY_INTERFACE_MODE_MII] = ETH_PHY_SEL_MII,
	[PHY_INTERFACE_MODE_GMII] = ETH_PHY_SEL_GMII,
	[PHY_INTERFACE_MODE_RGMII] = ETH_PHY_SEL_RGMII,
	[PHY_INTERFACE_MODE_RGMII_ID] = ETH_PHY_SEL_RGMII,
	[PHY_INTERFACE_MODE_SGMII] = ETH_PHY_SEL_SGMII,
	[PHY_INTERFACE_MODE_RMII] = ETH_PHY_SEL_RMII,
};

enum {
	
TX_RETIME_SRC_NA = 0,
	
TX_RETIME_SRC_TXCLK = 1,
	
TX_RETIME_SRC_CLK_125,
	
TX_RETIME_SRC_PHYCLK,
	
TX_RETIME_SRC_CLKGEN,
};


static u32 stih4xx_tx_retime_val[] = {
	[TX_RETIME_SRC_TXCLK] = STIH4XX_ETH_SEL_TXCLK_NOT_CLK125,
	[TX_RETIME_SRC_CLK_125] = 0x0,
	[TX_RETIME_SRC_PHYCLK] = STIH4XX_ETH_SEL_TX_RETIME_CLK,
	[TX_RETIME_SRC_CLKGEN] = STIH4XX_ETH_SEL_TX_RETIME_CLK
				 | STIH4XX_ETH_SEL_INTERNAL_NOTEXT_PHYCLK,
};


static void stih4xx_fix_retime_src(void *priv, u32 spd) { struct sti_dwmac *dwmac = priv; u32 src = dwmac->tx_retime_src; u32 reg = dwmac->ctrl_reg; u32 freq = 0; if (dwmac->interface == PHY_INTERFACE_MODE_MII) { src = TX_RETIME_SRC_TXCLK; } else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) { if (dwmac->ext_phyclk) { src = TX_RETIME_SRC_PHYCLK; } else { src = TX_RETIME_SRC_CLKGEN; freq = DWMAC_50MHZ; } } else if (IS_PHY_IF_MODE_RGMII(dwmac->interface)) { /* On GiGa clk source can be either ext or from clkgen */ if (spd == SPEED_1000) { freq = DWMAC_125MHZ; } else { /* Switch to clkgen for these speeds */ src = TX_RETIME_SRC_CLKGEN; if (spd == SPEED_100) freq = DWMAC_25MHZ; else if (spd == SPEED_10) freq = DWMAC_2_5MHZ; } } if (src == TX_RETIME_SRC_CLKGEN && freq) clk_set_rate(dwmac->clk, freq); regmap_update_bits(dwmac->regmap, reg, STIH4XX_RETIME_SRC_MASK, stih4xx_tx_retime_val[src]); }

Contributors

PersonTokensPropCommitsCommitProp
Srinivas Kandagatla11364.94%150.00%
Giuseppe Cavallaro6135.06%150.00%
Total174100.00%2100.00%


static void stid127_fix_retime_src(void *priv, u32 spd) { struct sti_dwmac *dwmac = priv; u32 reg = dwmac->ctrl_reg; u32 freq = 0; u32 val = 0; if (dwmac->interface == PHY_INTERFACE_MODE_MII) { val = STID127_ETH_SEL_INTERNAL_NOTEXT_TXCLK; } else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) { if (!dwmac->ext_phyclk) { val = STID127_ETH_SEL_INTERNAL_NOTEXT_PHYCLK; freq = DWMAC_50MHZ; } } else if (IS_PHY_IF_MODE_RGMII(dwmac->interface)) { val = STID127_ETH_SEL_INTERNAL_NOTEXT_TXCLK; if (spd == SPEED_1000) freq = DWMAC_125MHZ; else if (spd == SPEED_100) freq = DWMAC_25MHZ; else if (spd == SPEED_10) freq = DWMAC_2_5MHZ; } if (freq) clk_set_rate(dwmac->clk, freq); regmap_update_bits(dwmac->regmap, reg, STID127_RETIME_SRC_MASK, val); }

Contributors

PersonTokensPropCommitsCommitProp
Giuseppe Cavallaro13386.93%150.00%
Srinivas Kandagatla2013.07%150.00%
Total153100.00%2100.00%


static int sti_dwmac_set_mode(struct sti_dwmac *dwmac) { struct regmap *regmap = dwmac->regmap; int iface = dwmac->interface; u32 reg = dwmac->ctrl_reg; u32 val; if (dwmac->gmac_en) regmap_update_bits(regmap, reg, EN_MASK, EN); regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK, phy_intf_sels[iface]); val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII; regmap_update_bits(regmap, reg, ENMII_MASK, val); dwmac->fix_retime_src(dwmac, dwmac->speed); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Giuseppe Cavallaro9287.62%125.00%
Joachim Eastwood1312.38%375.00%
Total105100.00%4100.00%


static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, struct platform_device *pdev) { struct resource *res; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct regmap *regmap; int err; /* clk selection from extra syscfg register */ dwmac->clk_sel_reg = -ENXIO; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-clkconf"); if (res) dwmac->clk_sel_reg = res->start; regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon"); if (IS_ERR(regmap)) return PTR_ERR(regmap); err = of_property_read_u32_index(np, "st,syscon", 1, &dwmac->ctrl_reg); if (err) { dev_err(dev, "Can't get sysconfig ctrl offset (%d)\n", err); return err; } dwmac->interface = of_get_phy_mode(np); dwmac->regmap = regmap; dwmac->gmac_en = of_property_read_bool(np, "st,gmac_en"); dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk"); dwmac->tx_retime_src = TX_RETIME_SRC_NA; dwmac->speed = SPEED_100; if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) { const char *rs; dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN; err = of_property_read_string(np, "st,tx-retime-src", &rs); if (err < 0) { dev_warn(dev, "Use internal clock source\n"); } else { if (!strcasecmp(rs, "clk_125")) dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125; else if (!strcasecmp(rs, "txclk")) dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK; } dwmac->speed = SPEED_1000; } dwmac->clk = devm_clk_get(dev, "sti-ethclk"); if (IS_ERR(dwmac->clk)) { dev_warn(dev, "No phy clock provided...\n"); dwmac->clk = NULL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Srinivas Kandagatla18358.47%116.67%
Giuseppe Cavallaro8226.20%233.33%
Peter Griffin3410.86%116.67%
Joachim Eastwood113.51%116.67%
Geert Uytterhoeven30.96%116.67%
Total313100.00%6100.00%


static int sti_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; const struct sti_dwmac_of_data *data; struct stmmac_resources stmmac_res; struct sti_dwmac *dwmac; int ret; data = of_device_get_match_data(&pdev->dev); if (!data) { dev_err(&pdev->dev, "No OF match data provided\n"); return -EINVAL; } ret = stmmac_get_platform_resources(pdev, &stmmac_res); if (ret) return ret; plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); if (IS_ERR(plat_dat)) return PTR_ERR(plat_dat); dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); if (!dwmac) { ret = -ENOMEM; goto err_remove_config_dt; } ret = sti_dwmac_parse_data(dwmac, pdev); if (ret) { dev_err(&pdev->dev, "Unable to parse OF data\n"); goto err_remove_config_dt; } dwmac->fix_retime_src = data->fix_retime_src; plat_dat->bsp_priv = dwmac; plat_dat->fix_mac_speed = data->fix_retime_src; ret = clk_prepare_enable(dwmac->clk); if (ret) goto err_remove_config_dt; ret = sti_dwmac_set_mode(dwmac); if (ret) goto disable_clk; ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) goto disable_clk; return 0; disable_clk: clk_disable_unprepare(dwmac->clk); err_remove_config_dt: stmmac_remove_config_dt(pdev, plat_dat); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Joachim Eastwood17465.41%675.00%
Srinivas Kandagatla6925.94%112.50%
Johan Hovold238.65%112.50%
Total266100.00%8100.00%


static int sti_dwmac_remove(struct platform_device *pdev) { struct sti_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev); int ret = stmmac_dvr_remove(&pdev->dev); clk_disable_unprepare(dwmac->clk); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Joachim Eastwood45100.00%1100.00%
Total45100.00%1100.00%

#ifdef CONFIG_PM_SLEEP
static int sti_dwmac_suspend(struct device *dev) { struct sti_dwmac *dwmac = get_stmmac_bsp_priv(dev); int ret = stmmac_suspend(dev); clk_disable_unprepare(dwmac->clk); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Joachim Eastwood39100.00%1100.00%
Total39100.00%1100.00%


static int sti_dwmac_resume(struct device *dev) { struct sti_dwmac *dwmac = get_stmmac_bsp_priv(dev); clk_prepare_enable(dwmac->clk); sti_dwmac_set_mode(dwmac); return stmmac_resume(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Joachim Eastwood39100.00%3100.00%
Total39100.00%3100.00%

#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(sti_dwmac_pm_ops, sti_dwmac_suspend, sti_dwmac_resume); static const struct sti_dwmac_of_data stih4xx_dwmac_data = { .fix_retime_src = stih4xx_fix_retime_src, }; static const struct sti_dwmac_of_data stid127_dwmac_data = { .fix_retime_src = stid127_fix_retime_src, }; static const struct of_device_id sti_dwmac_match[] = { { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data}, { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data}, { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data}, { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data}, { } }; MODULE_DEVICE_TABLE(of, sti_dwmac_match); static struct platform_driver sti_dwmac_driver = { .probe = sti_dwmac_probe, .remove = sti_dwmac_remove, .driver = { .name = "sti-dwmac", .pm = &sti_dwmac_pm_ops, .of_match_table = sti_dwmac_match, }, }; module_platform_driver(sti_dwmac_driver); MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@st.com>"); MODULE_DESCRIPTION("STMicroelectronics DWMAC Specific Glue layer"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Srinivas Kandagatla57635.67%15.88%
Joachim Eastwood51732.01%952.94%
Giuseppe Cavallaro45828.36%317.65%
Peter Griffin352.17%15.88%
Johan Hovold231.42%15.88%
Andy Shevchenko30.19%15.88%
Geert Uytterhoeven30.19%15.88%
Total1615100.00%17100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.