cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dwmac-visconti.c (8633B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Toshiba Visconti Ethernet Support
      3 *
      4 * (C) Copyright 2020 TOSHIBA CORPORATION
      5 * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/of_device.h>
     10#include <linux/of_net.h>
     11#include <linux/stmmac.h>
     12
     13#include "stmmac_platform.h"
     14#include "dwmac4.h"
     15
     16#define REG_ETHER_CONTROL	0x52D4
     17#define ETHER_ETH_CONTROL_RESET BIT(17)
     18
     19#define REG_ETHER_CLOCK_SEL	0x52D0
     20#define ETHER_CLK_SEL_TX_CLK_EN BIT(0)
     21#define ETHER_CLK_SEL_RX_CLK_EN BIT(1)
     22#define ETHER_CLK_SEL_RMII_CLK_EN BIT(2)
     23#define ETHER_CLK_SEL_RMII_CLK_RST BIT(3)
     24#define ETHER_CLK_SEL_DIV_SEL_2 BIT(4)
     25#define ETHER_CLK_SEL_DIV_SEL_20 0
     26#define ETHER_CLK_SEL_FREQ_SEL_125M	(BIT(9) | BIT(8))
     27#define ETHER_CLK_SEL_FREQ_SEL_50M	BIT(9)
     28#define ETHER_CLK_SEL_FREQ_SEL_25M	BIT(8)
     29#define ETHER_CLK_SEL_FREQ_SEL_2P5M	0
     30#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN 0
     31#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC BIT(10)
     32#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV BIT(11)
     33#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_IN  0
     34#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC BIT(12)
     35#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV BIT(13)
     36#define ETHER_CLK_SEL_TX_CLK_O_TX_I	 0
     37#define ETHER_CLK_SEL_TX_CLK_O_RMII_I	 BIT(14)
     38#define ETHER_CLK_SEL_TX_O_E_N_IN	 BIT(15)
     39#define ETHER_CLK_SEL_RMII_CLK_SEL_IN	 0
     40#define ETHER_CLK_SEL_RMII_CLK_SEL_RX_C	 BIT(16)
     41
     42#define ETHER_CLK_SEL_RX_TX_CLK_EN (ETHER_CLK_SEL_RX_CLK_EN | ETHER_CLK_SEL_TX_CLK_EN)
     43
     44#define ETHER_CONFIG_INTF_MII 0
     45#define ETHER_CONFIG_INTF_RGMII BIT(0)
     46#define ETHER_CONFIG_INTF_RMII BIT(2)
     47
     48struct visconti_eth {
     49	void __iomem *reg;
     50	u32 phy_intf_sel;
     51	struct clk *phy_ref_clk;
     52	struct device *dev;
     53	spinlock_t lock; /* lock to protect register update */
     54};
     55
     56static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed)
     57{
     58	struct visconti_eth *dwmac = priv;
     59	struct net_device *netdev = dev_get_drvdata(dwmac->dev);
     60	unsigned int val, clk_sel_val = 0;
     61	unsigned long flags;
     62
     63	spin_lock_irqsave(&dwmac->lock, flags);
     64
     65	/* adjust link */
     66	val = readl(dwmac->reg + MAC_CTRL_REG);
     67	val &= ~(GMAC_CONFIG_PS | GMAC_CONFIG_FES);
     68
     69	switch (speed) {
     70	case SPEED_1000:
     71		if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
     72			clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M;
     73		break;
     74	case SPEED_100:
     75		if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
     76			clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_25M;
     77		if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII)
     78			clk_sel_val = ETHER_CLK_SEL_DIV_SEL_2;
     79		val |= GMAC_CONFIG_PS | GMAC_CONFIG_FES;
     80		break;
     81	case SPEED_10:
     82		if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII)
     83			clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_2P5M;
     84		if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII)
     85			clk_sel_val = ETHER_CLK_SEL_DIV_SEL_20;
     86		val |= GMAC_CONFIG_PS;
     87		break;
     88	default:
     89		/* No bit control */
     90		netdev_err(netdev, "Unsupported speed request (%d)", speed);
     91		spin_unlock_irqrestore(&dwmac->lock, flags);
     92		return;
     93	}
     94
     95	writel(val, dwmac->reg + MAC_CTRL_REG);
     96
     97	/* Stop internal clock */
     98	val = readl(dwmac->reg + REG_ETHER_CLOCK_SEL);
     99	val &= ~(ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN);
    100	val |= ETHER_CLK_SEL_TX_O_E_N_IN;
    101	writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
    102
    103	/* Set Clock-Mux, Start clock, Set TX_O direction */
    104	switch (dwmac->phy_intf_sel) {
    105	case ETHER_CONFIG_INTF_RGMII:
    106		val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC;
    107		writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
    108
    109		val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
    110		writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
    111
    112		val &= ~ETHER_CLK_SEL_TX_O_E_N_IN;
    113		writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
    114		break;
    115	case ETHER_CONFIG_INTF_RMII:
    116		val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV |
    117			ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN |
    118			ETHER_CLK_SEL_RMII_CLK_SEL_RX_C;
    119		writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
    120
    121		val |= ETHER_CLK_SEL_RMII_CLK_RST;
    122		writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
    123
    124		val |= ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN;
    125		writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
    126		break;
    127	case ETHER_CONFIG_INTF_MII:
    128	default:
    129		val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC |
    130			ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN;
    131		writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
    132
    133		val |= ETHER_CLK_SEL_RX_TX_CLK_EN;
    134		writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL);
    135		break;
    136	}
    137
    138	spin_unlock_irqrestore(&dwmac->lock, flags);
    139}
    140
    141static int visconti_eth_init_hw(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat)
    142{
    143	struct visconti_eth *dwmac = plat_dat->bsp_priv;
    144	unsigned int reg_val, clk_sel_val;
    145
    146	switch (plat_dat->phy_interface) {
    147	case PHY_INTERFACE_MODE_RGMII:
    148	case PHY_INTERFACE_MODE_RGMII_ID:
    149	case PHY_INTERFACE_MODE_RGMII_RXID:
    150	case PHY_INTERFACE_MODE_RGMII_TXID:
    151		dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RGMII;
    152		break;
    153	case PHY_INTERFACE_MODE_MII:
    154		dwmac->phy_intf_sel = ETHER_CONFIG_INTF_MII;
    155		break;
    156	case PHY_INTERFACE_MODE_RMII:
    157		dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RMII;
    158		break;
    159	default:
    160		dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n", plat_dat->phy_interface);
    161		return -EOPNOTSUPP;
    162	}
    163
    164	reg_val = dwmac->phy_intf_sel;
    165	writel(reg_val, dwmac->reg + REG_ETHER_CONTROL);
    166
    167	/* Enable TX/RX clock */
    168	clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M;
    169	writel(clk_sel_val, dwmac->reg + REG_ETHER_CLOCK_SEL);
    170
    171	writel((clk_sel_val | ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN),
    172	       dwmac->reg + REG_ETHER_CLOCK_SEL);
    173
    174	/* release internal-reset */
    175	reg_val |= ETHER_ETH_CONTROL_RESET;
    176	writel(reg_val, dwmac->reg + REG_ETHER_CONTROL);
    177
    178	return 0;
    179}
    180
    181static int visconti_eth_clock_probe(struct platform_device *pdev,
    182				    struct plat_stmmacenet_data *plat_dat)
    183{
    184	struct visconti_eth *dwmac = plat_dat->bsp_priv;
    185	int err;
    186
    187	dwmac->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk");
    188	if (IS_ERR(dwmac->phy_ref_clk))
    189		return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->phy_ref_clk),
    190				     "phy_ref_clk clock not found.\n");
    191
    192	err = clk_prepare_enable(dwmac->phy_ref_clk);
    193	if (err < 0) {
    194		dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n", err);
    195		return err;
    196	}
    197
    198	return 0;
    199}
    200
    201static int visconti_eth_clock_remove(struct platform_device *pdev)
    202{
    203	struct visconti_eth *dwmac = get_stmmac_bsp_priv(&pdev->dev);
    204	struct net_device *ndev = platform_get_drvdata(pdev);
    205	struct stmmac_priv *priv = netdev_priv(ndev);
    206
    207	clk_disable_unprepare(dwmac->phy_ref_clk);
    208	clk_disable_unprepare(priv->plat->stmmac_clk);
    209
    210	return 0;
    211}
    212
    213static int visconti_eth_dwmac_probe(struct platform_device *pdev)
    214{
    215	struct plat_stmmacenet_data *plat_dat;
    216	struct stmmac_resources stmmac_res;
    217	struct visconti_eth *dwmac;
    218	int ret;
    219
    220	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
    221	if (ret)
    222		return ret;
    223
    224	plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
    225	if (IS_ERR(plat_dat))
    226		return PTR_ERR(plat_dat);
    227
    228	dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
    229	if (!dwmac) {
    230		ret = -ENOMEM;
    231		goto remove_config;
    232	}
    233
    234	spin_lock_init(&dwmac->lock);
    235	dwmac->reg = stmmac_res.addr;
    236	dwmac->dev = &pdev->dev;
    237	plat_dat->bsp_priv = dwmac;
    238	plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed;
    239
    240	ret = visconti_eth_clock_probe(pdev, plat_dat);
    241	if (ret)
    242		goto remove_config;
    243
    244	visconti_eth_init_hw(pdev, plat_dat);
    245
    246	plat_dat->dma_cfg->aal = 1;
    247
    248	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
    249	if (ret)
    250		goto remove;
    251
    252	return ret;
    253
    254remove:
    255	visconti_eth_clock_remove(pdev);
    256remove_config:
    257	stmmac_remove_config_dt(pdev, plat_dat);
    258
    259	return ret;
    260}
    261
    262static int visconti_eth_dwmac_remove(struct platform_device *pdev)
    263{
    264	struct net_device *ndev = platform_get_drvdata(pdev);
    265	struct stmmac_priv *priv = netdev_priv(ndev);
    266	int err;
    267
    268	err = stmmac_pltfr_remove(pdev);
    269	if (err < 0)
    270		dev_err(&pdev->dev, "failed to remove platform: %d\n", err);
    271
    272	err = visconti_eth_clock_remove(pdev);
    273	if (err < 0)
    274		dev_err(&pdev->dev, "failed to remove clock: %d\n", err);
    275
    276	stmmac_remove_config_dt(pdev, priv->plat);
    277
    278	return err;
    279}
    280
    281static const struct of_device_id visconti_eth_dwmac_match[] = {
    282	{ .compatible = "toshiba,visconti-dwmac" },
    283	{ }
    284};
    285MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match);
    286
    287static struct platform_driver visconti_eth_dwmac_driver = {
    288	.probe  = visconti_eth_dwmac_probe,
    289	.remove = visconti_eth_dwmac_remove,
    290	.driver = {
    291		.name           = "visconti-eth-dwmac",
    292		.of_match_table = visconti_eth_dwmac_match,
    293	},
    294};
    295module_platform_driver(visconti_eth_dwmac_driver);
    296
    297MODULE_AUTHOR("Toshiba");
    298MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver");
    299MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp");
    300MODULE_LICENSE("GPL v2");