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

cpsw-phy-sel.c (5425B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Texas Instruments Ethernet Switch Driver
      3 *
      4 * Copyright (C) 2013 Texas Instruments
      5 *
      6 * Module Author: Mugunthan V N <mugunthanvnm@ti.com>
      7 *
      8 */
      9
     10#include <linux/platform_device.h>
     11#include <linux/init.h>
     12#include <linux/netdevice.h>
     13#include <linux/phy.h>
     14#include <linux/of.h>
     15#include <linux/of_device.h>
     16
     17#include "cpsw.h"
     18
     19/* AM33xx SoC specific definitions for the CONTROL port */
     20#define AM33XX_GMII_SEL_MODE_MII	0
     21#define AM33XX_GMII_SEL_MODE_RMII	1
     22#define AM33XX_GMII_SEL_MODE_RGMII	2
     23
     24#define AM33XX_GMII_SEL_RMII2_IO_CLK_EN	BIT(7)
     25#define AM33XX_GMII_SEL_RMII1_IO_CLK_EN	BIT(6)
     26#define AM33XX_GMII_SEL_RGMII2_IDMODE	BIT(5)
     27#define AM33XX_GMII_SEL_RGMII1_IDMODE	BIT(4)
     28
     29#define GMII_SEL_MODE_MASK		0x3
     30
     31struct cpsw_phy_sel_priv {
     32	struct device	*dev;
     33	u32 __iomem	*gmii_sel;
     34	bool		rmii_clock_external;
     35	void (*cpsw_phy_sel)(struct cpsw_phy_sel_priv *priv,
     36			     phy_interface_t phy_mode, int slave);
     37};
     38
     39
     40static void cpsw_gmii_sel_am3352(struct cpsw_phy_sel_priv *priv,
     41				 phy_interface_t phy_mode, int slave)
     42{
     43	u32 reg;
     44	u32 mask;
     45	u32 mode = 0;
     46	bool rgmii_id = false;
     47
     48	reg = readl(priv->gmii_sel);
     49
     50	switch (phy_mode) {
     51	case PHY_INTERFACE_MODE_RMII:
     52		mode = AM33XX_GMII_SEL_MODE_RMII;
     53		break;
     54
     55	case PHY_INTERFACE_MODE_RGMII:
     56		mode = AM33XX_GMII_SEL_MODE_RGMII;
     57		break;
     58
     59	case PHY_INTERFACE_MODE_RGMII_ID:
     60	case PHY_INTERFACE_MODE_RGMII_RXID:
     61	case PHY_INTERFACE_MODE_RGMII_TXID:
     62		mode = AM33XX_GMII_SEL_MODE_RGMII;
     63		rgmii_id = true;
     64		break;
     65
     66	default:
     67		dev_warn(priv->dev,
     68			 "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
     69			phy_modes(phy_mode));
     70		fallthrough;
     71	case PHY_INTERFACE_MODE_MII:
     72		mode = AM33XX_GMII_SEL_MODE_MII;
     73		break;
     74	}
     75
     76	mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6);
     77	mask |= BIT(slave + 4);
     78	mode <<= slave * 2;
     79
     80	if (priv->rmii_clock_external) {
     81		if (slave == 0)
     82			mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN;
     83		else
     84			mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN;
     85	}
     86
     87	if (rgmii_id) {
     88		if (slave == 0)
     89			mode |= AM33XX_GMII_SEL_RGMII1_IDMODE;
     90		else
     91			mode |= AM33XX_GMII_SEL_RGMII2_IDMODE;
     92	}
     93
     94	reg &= ~mask;
     95	reg |= mode;
     96
     97	writel(reg, priv->gmii_sel);
     98}
     99
    100static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv,
    101				 phy_interface_t phy_mode, int slave)
    102{
    103	u32 reg;
    104	u32 mask;
    105	u32 mode = 0;
    106
    107	reg = readl(priv->gmii_sel);
    108
    109	switch (phy_mode) {
    110	case PHY_INTERFACE_MODE_RMII:
    111		mode = AM33XX_GMII_SEL_MODE_RMII;
    112		break;
    113
    114	case PHY_INTERFACE_MODE_RGMII:
    115	case PHY_INTERFACE_MODE_RGMII_ID:
    116	case PHY_INTERFACE_MODE_RGMII_RXID:
    117	case PHY_INTERFACE_MODE_RGMII_TXID:
    118		mode = AM33XX_GMII_SEL_MODE_RGMII;
    119		break;
    120
    121	default:
    122		dev_warn(priv->dev,
    123			 "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
    124			phy_modes(phy_mode));
    125		fallthrough;
    126	case PHY_INTERFACE_MODE_MII:
    127		mode = AM33XX_GMII_SEL_MODE_MII;
    128		break;
    129	}
    130
    131	switch (slave) {
    132	case 0:
    133		mask = GMII_SEL_MODE_MASK;
    134		break;
    135	case 1:
    136		mask = GMII_SEL_MODE_MASK << 4;
    137		mode <<= 4;
    138		break;
    139	default:
    140		dev_err(priv->dev, "invalid slave number...\n");
    141		return;
    142	}
    143
    144	if (priv->rmii_clock_external)
    145		dev_err(priv->dev, "RMII External clock is not supported\n");
    146
    147	reg &= ~mask;
    148	reg |= mode;
    149
    150	writel(reg, priv->gmii_sel);
    151}
    152
    153static struct platform_driver cpsw_phy_sel_driver;
    154static int match(struct device *dev, const void *data)
    155{
    156	const struct device_node *node = (const struct device_node *)data;
    157	return dev->of_node == node &&
    158		dev->driver == &cpsw_phy_sel_driver.driver;
    159}
    160
    161void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave)
    162{
    163	struct device_node *node;
    164	struct cpsw_phy_sel_priv *priv;
    165
    166	node = of_parse_phandle(dev->of_node, "cpsw-phy-sel", 0);
    167	if (!node) {
    168		node = of_get_child_by_name(dev->of_node, "cpsw-phy-sel");
    169		if (!node) {
    170			dev_err(dev, "Phy mode driver DT not found\n");
    171			return;
    172		}
    173	}
    174
    175	dev = bus_find_device(&platform_bus_type, NULL, node, match);
    176	if (!dev) {
    177		dev_err(dev, "unable to find platform device for %pOF\n", node);
    178		goto out;
    179	}
    180
    181	priv = dev_get_drvdata(dev);
    182
    183	priv->cpsw_phy_sel(priv, phy_mode, slave);
    184
    185	put_device(dev);
    186out:
    187	of_node_put(node);
    188}
    189EXPORT_SYMBOL_GPL(cpsw_phy_sel);
    190
    191static const struct of_device_id cpsw_phy_sel_id_table[] = {
    192	{
    193		.compatible	= "ti,am3352-cpsw-phy-sel",
    194		.data		= &cpsw_gmii_sel_am3352,
    195	},
    196	{
    197		.compatible	= "ti,dra7xx-cpsw-phy-sel",
    198		.data		= &cpsw_gmii_sel_dra7xx,
    199	},
    200	{
    201		.compatible	= "ti,am43xx-cpsw-phy-sel",
    202		.data		= &cpsw_gmii_sel_am3352,
    203	},
    204	{}
    205};
    206
    207static int cpsw_phy_sel_probe(struct platform_device *pdev)
    208{
    209	const struct of_device_id *of_id;
    210	struct cpsw_phy_sel_priv *priv;
    211
    212	of_id = of_match_node(cpsw_phy_sel_id_table, pdev->dev.of_node);
    213	if (!of_id)
    214		return -EINVAL;
    215
    216	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    217	if (!priv) {
    218		dev_err(&pdev->dev, "unable to alloc memory for cpsw phy sel\n");
    219		return -ENOMEM;
    220	}
    221
    222	priv->dev = &pdev->dev;
    223	priv->cpsw_phy_sel = of_id->data;
    224
    225	priv->gmii_sel = devm_platform_ioremap_resource_byname(pdev, "gmii-sel");
    226	if (IS_ERR(priv->gmii_sel))
    227		return PTR_ERR(priv->gmii_sel);
    228
    229	if (of_find_property(pdev->dev.of_node, "rmii-clock-ext", NULL))
    230		priv->rmii_clock_external = true;
    231
    232	dev_set_drvdata(&pdev->dev, priv);
    233
    234	return 0;
    235}
    236
    237static struct platform_driver cpsw_phy_sel_driver = {
    238	.probe		= cpsw_phy_sel_probe,
    239	.driver		= {
    240		.name	= "cpsw-phy-sel",
    241		.of_match_table = cpsw_phy_sel_id_table,
    242	},
    243};
    244builtin_platform_driver(cpsw_phy_sel_driver);