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

phy-gmii-sel.c (10613B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Texas Instruments CPSW Port's PHY Interface Mode selection Driver
      4 *
      5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
      6 *
      7 * Based on cpsw-phy-sel.c driver created by Mugunthan V N <mugunthanvnm@ti.com>
      8 */
      9
     10#include <linux/platform_device.h>
     11#include <linux/module.h>
     12#include <linux/mfd/syscon.h>
     13#include <linux/of.h>
     14#include <linux/of_address.h>
     15#include <linux/of_net.h>
     16#include <linux/phy.h>
     17#include <linux/phy/phy.h>
     18#include <linux/regmap.h>
     19
     20/* AM33xx SoC specific definitions for the CONTROL port */
     21#define AM33XX_GMII_SEL_MODE_MII	0
     22#define AM33XX_GMII_SEL_MODE_RMII	1
     23#define AM33XX_GMII_SEL_MODE_RGMII	2
     24
     25enum {
     26	PHY_GMII_SEL_PORT_MODE = 0,
     27	PHY_GMII_SEL_RGMII_ID_MODE,
     28	PHY_GMII_SEL_RMII_IO_CLK_EN,
     29	PHY_GMII_SEL_LAST,
     30};
     31
     32struct phy_gmii_sel_phy_priv {
     33	struct phy_gmii_sel_priv *priv;
     34	u32		id;
     35	struct phy	*if_phy;
     36	int		rmii_clock_external;
     37	int		phy_if_mode;
     38	struct regmap_field *fields[PHY_GMII_SEL_LAST];
     39};
     40
     41struct phy_gmii_sel_soc_data {
     42	u32 num_ports;
     43	u32 features;
     44	const struct reg_field (*regfields)[PHY_GMII_SEL_LAST];
     45	bool use_of_data;
     46};
     47
     48struct phy_gmii_sel_priv {
     49	struct device *dev;
     50	const struct phy_gmii_sel_soc_data *soc_data;
     51	struct regmap *regmap;
     52	struct phy_provider *phy_provider;
     53	struct phy_gmii_sel_phy_priv *if_phys;
     54	u32 num_ports;
     55	u32 reg_offset;
     56};
     57
     58static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
     59{
     60	struct phy_gmii_sel_phy_priv *if_phy = phy_get_drvdata(phy);
     61	const struct phy_gmii_sel_soc_data *soc_data = if_phy->priv->soc_data;
     62	struct device *dev = if_phy->priv->dev;
     63	struct regmap_field *regfield;
     64	int ret, rgmii_id = 0;
     65	u32 gmii_sel_mode = 0;
     66
     67	if (mode != PHY_MODE_ETHERNET)
     68		return -EINVAL;
     69
     70	switch (submode) {
     71	case PHY_INTERFACE_MODE_RMII:
     72		gmii_sel_mode = AM33XX_GMII_SEL_MODE_RMII;
     73		break;
     74
     75	case PHY_INTERFACE_MODE_RGMII:
     76	case PHY_INTERFACE_MODE_RGMII_RXID:
     77		gmii_sel_mode = AM33XX_GMII_SEL_MODE_RGMII;
     78		break;
     79
     80	case PHY_INTERFACE_MODE_RGMII_ID:
     81	case PHY_INTERFACE_MODE_RGMII_TXID:
     82		gmii_sel_mode = AM33XX_GMII_SEL_MODE_RGMII;
     83		rgmii_id = 1;
     84		break;
     85
     86	case PHY_INTERFACE_MODE_MII:
     87	case PHY_INTERFACE_MODE_GMII:
     88		gmii_sel_mode = AM33XX_GMII_SEL_MODE_MII;
     89		break;
     90
     91	default:
     92		dev_warn(dev, "port%u: unsupported mode: \"%s\"\n",
     93			 if_phy->id, phy_modes(submode));
     94		return -EINVAL;
     95	}
     96
     97	if_phy->phy_if_mode = submode;
     98
     99	dev_dbg(dev, "%s id:%u mode:%u rgmii_id:%d rmii_clk_ext:%d\n",
    100		__func__, if_phy->id, submode, rgmii_id,
    101		if_phy->rmii_clock_external);
    102
    103	regfield = if_phy->fields[PHY_GMII_SEL_PORT_MODE];
    104	ret = regmap_field_write(regfield, gmii_sel_mode);
    105	if (ret) {
    106		dev_err(dev, "port%u: set mode fail %d", if_phy->id, ret);
    107		return ret;
    108	}
    109
    110	if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE) &&
    111	    if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE]) {
    112		regfield = if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE];
    113		ret = regmap_field_write(regfield, rgmii_id);
    114		if (ret)
    115			return ret;
    116	}
    117
    118	if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
    119	    if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN]) {
    120		regfield = if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN];
    121		ret = regmap_field_write(regfield,
    122					 if_phy->rmii_clock_external);
    123	}
    124
    125	return 0;
    126}
    127
    128static const
    129struct reg_field phy_gmii_sel_fields_am33xx[][PHY_GMII_SEL_LAST] = {
    130	{
    131		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x650, 0, 1),
    132		[PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x650, 4, 4),
    133		[PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD(0x650, 6, 6),
    134	},
    135	{
    136		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x650, 2, 3),
    137		[PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD(0x650, 5, 5),
    138		[PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD(0x650, 7, 7),
    139	},
    140};
    141
    142static const
    143struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am33xx = {
    144	.num_ports = 2,
    145	.features = BIT(PHY_GMII_SEL_RGMII_ID_MODE) |
    146		    BIT(PHY_GMII_SEL_RMII_IO_CLK_EN),
    147	.regfields = phy_gmii_sel_fields_am33xx,
    148};
    149
    150static const
    151struct reg_field phy_gmii_sel_fields_dra7[][PHY_GMII_SEL_LAST] = {
    152	{
    153		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x554, 0, 1),
    154	},
    155	{
    156		[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x554, 4, 5),
    157	},
    158};
    159
    160static const
    161struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dra7 = {
    162	.num_ports = 2,
    163	.regfields = phy_gmii_sel_fields_dra7,
    164};
    165
    166static const
    167struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814 = {
    168	.num_ports = 2,
    169	.features = BIT(PHY_GMII_SEL_RGMII_ID_MODE),
    170	.regfields = phy_gmii_sel_fields_am33xx,
    171};
    172
    173static const
    174struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = {
    175	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x0, 0, 2), },
    176	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4, 0, 2), },
    177	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x8, 0, 2), },
    178	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0xC, 0, 2), },
    179	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x10, 0, 2), },
    180	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x14, 0, 2), },
    181	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x18, 0, 2), },
    182	{ [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x1C, 0, 2), },
    183};
    184
    185static const
    186struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
    187	.use_of_data = true,
    188	.regfields = phy_gmii_sel_fields_am654,
    189};
    190
    191static const struct of_device_id phy_gmii_sel_id_table[] = {
    192	{
    193		.compatible	= "ti,am3352-phy-gmii-sel",
    194		.data		= &phy_gmii_sel_soc_am33xx,
    195	},
    196	{
    197		.compatible	= "ti,dra7xx-phy-gmii-sel",
    198		.data		= &phy_gmii_sel_soc_dra7,
    199	},
    200	{
    201		.compatible	= "ti,am43xx-phy-gmii-sel",
    202		.data		= &phy_gmii_sel_soc_am33xx,
    203	},
    204	{
    205		.compatible	= "ti,dm814-phy-gmii-sel",
    206		.data		= &phy_gmii_sel_soc_dm814,
    207	},
    208	{
    209		.compatible	= "ti,am654-phy-gmii-sel",
    210		.data		= &phy_gmii_sel_soc_am654,
    211	},
    212	{}
    213};
    214MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table);
    215
    216static const struct phy_ops phy_gmii_sel_ops = {
    217	.set_mode	= phy_gmii_sel_mode,
    218	.owner		= THIS_MODULE,
    219};
    220
    221static struct phy *phy_gmii_sel_of_xlate(struct device *dev,
    222					 struct of_phandle_args *args)
    223{
    224	struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev);
    225	int phy_id = args->args[0];
    226
    227	if (args->args_count < 1)
    228		return ERR_PTR(-EINVAL);
    229	if (!priv || !priv->if_phys)
    230		return ERR_PTR(-ENODEV);
    231	if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) &&
    232	    args->args_count < 2)
    233		return ERR_PTR(-EINVAL);
    234	if (phy_id > priv->num_ports)
    235		return ERR_PTR(-EINVAL);
    236	if (phy_id != priv->if_phys[phy_id - 1].id)
    237		return ERR_PTR(-EINVAL);
    238
    239	phy_id--;
    240	if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN))
    241		priv->if_phys[phy_id].rmii_clock_external = args->args[1];
    242	dev_dbg(dev, "%s id:%u ext:%d\n", __func__,
    243		priv->if_phys[phy_id].id, args->args[1]);
    244
    245	return priv->if_phys[phy_id].if_phy;
    246}
    247
    248static int phy_gmii_init_phy(struct phy_gmii_sel_priv *priv, int port,
    249			     struct phy_gmii_sel_phy_priv *if_phy)
    250{
    251	const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
    252	struct device *dev = priv->dev;
    253	const struct reg_field *fields;
    254	struct regmap_field *regfield;
    255	struct reg_field field;
    256	int ret;
    257
    258	if_phy->id = port;
    259	if_phy->priv = priv;
    260
    261	fields = soc_data->regfields[port - 1];
    262	field = *fields++;
    263	field.reg += priv->reg_offset;
    264	dev_dbg(dev, "%s field %x %d %d\n", __func__,
    265		field.reg, field.msb, field.lsb);
    266
    267	regfield = devm_regmap_field_alloc(dev, priv->regmap, field);
    268	if (IS_ERR(regfield))
    269		return PTR_ERR(regfield);
    270	if_phy->fields[PHY_GMII_SEL_PORT_MODE] = regfield;
    271
    272	field = *fields++;
    273	field.reg += priv->reg_offset;
    274	if (soc_data->features & BIT(PHY_GMII_SEL_RGMII_ID_MODE)) {
    275		regfield = devm_regmap_field_alloc(dev,
    276						   priv->regmap,
    277						   field);
    278		if (IS_ERR(regfield))
    279			return PTR_ERR(regfield);
    280		if_phy->fields[PHY_GMII_SEL_RGMII_ID_MODE] = regfield;
    281		dev_dbg(dev, "%s field %x %d %d\n", __func__,
    282			field.reg, field.msb, field.lsb);
    283	}
    284
    285	field = *fields;
    286	field.reg += priv->reg_offset;
    287	if (soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN)) {
    288		regfield = devm_regmap_field_alloc(dev,
    289						   priv->regmap,
    290						   field);
    291		if (IS_ERR(regfield))
    292			return PTR_ERR(regfield);
    293		if_phy->fields[PHY_GMII_SEL_RMII_IO_CLK_EN] = regfield;
    294		dev_dbg(dev, "%s field %x %d %d\n", __func__,
    295			field.reg, field.msb, field.lsb);
    296	}
    297
    298	if_phy->if_phy = devm_phy_create(dev,
    299					 priv->dev->of_node,
    300					 &phy_gmii_sel_ops);
    301	if (IS_ERR(if_phy->if_phy)) {
    302		ret = PTR_ERR(if_phy->if_phy);
    303		dev_err(dev, "Failed to create phy%d %d\n", port, ret);
    304		return ret;
    305	}
    306	phy_set_drvdata(if_phy->if_phy, if_phy);
    307
    308	return 0;
    309}
    310
    311static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
    312{
    313	const struct phy_gmii_sel_soc_data *soc_data = priv->soc_data;
    314	struct phy_gmii_sel_phy_priv *if_phys;
    315	struct device *dev = priv->dev;
    316	int i, ret;
    317
    318	if (soc_data->use_of_data) {
    319		const __be32 *offset;
    320		u64 size;
    321
    322		offset = of_get_address(dev->of_node, 0, &size, NULL);
    323		if (!offset)
    324			return -EINVAL;
    325		priv->num_ports = size / sizeof(u32);
    326		if (!priv->num_ports)
    327			return -EINVAL;
    328		priv->reg_offset = __be32_to_cpu(*offset);
    329	}
    330
    331	if_phys = devm_kcalloc(dev, priv->num_ports,
    332			       sizeof(*if_phys), GFP_KERNEL);
    333	if (!if_phys)
    334		return -ENOMEM;
    335	dev_dbg(dev, "%s %d\n", __func__, priv->num_ports);
    336
    337	for (i = 0; i < priv->num_ports; i++) {
    338		ret = phy_gmii_init_phy(priv, i + 1, &if_phys[i]);
    339		if (ret)
    340			return ret;
    341	}
    342
    343	priv->if_phys = if_phys;
    344	return 0;
    345}
    346
    347static int phy_gmii_sel_probe(struct platform_device *pdev)
    348{
    349	struct device *dev = &pdev->dev;
    350	struct device_node *node = dev->of_node;
    351	const struct of_device_id *of_id;
    352	struct phy_gmii_sel_priv *priv;
    353	int ret;
    354
    355	of_id = of_match_node(phy_gmii_sel_id_table, pdev->dev.of_node);
    356	if (!of_id)
    357		return -EINVAL;
    358
    359	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    360	if (!priv)
    361		return -ENOMEM;
    362
    363	priv->dev = &pdev->dev;
    364	priv->soc_data = of_id->data;
    365	priv->num_ports = priv->soc_data->num_ports;
    366
    367	priv->regmap = syscon_node_to_regmap(node->parent);
    368	if (IS_ERR(priv->regmap)) {
    369		ret = PTR_ERR(priv->regmap);
    370		dev_err(dev, "Failed to get syscon %d\n", ret);
    371		return ret;
    372	}
    373
    374	ret = phy_gmii_sel_init_ports(priv);
    375	if (ret)
    376		return ret;
    377
    378	dev_set_drvdata(&pdev->dev, priv);
    379
    380	priv->phy_provider =
    381		devm_of_phy_provider_register(dev,
    382					      phy_gmii_sel_of_xlate);
    383	if (IS_ERR(priv->phy_provider)) {
    384		ret = PTR_ERR(priv->phy_provider);
    385		dev_err(dev, "Failed to create phy provider %d\n", ret);
    386		return ret;
    387	}
    388
    389	return 0;
    390}
    391
    392static struct platform_driver phy_gmii_sel_driver = {
    393	.probe		= phy_gmii_sel_probe,
    394	.driver		= {
    395		.name	= "phy-gmii-sel",
    396		.of_match_table = phy_gmii_sel_id_table,
    397	},
    398};
    399module_platform_driver(phy_gmii_sel_driver);
    400
    401MODULE_LICENSE("GPL v2");
    402MODULE_AUTHOR("Grygorii Strashko <grygorii.strashko@ti.com>");
    403MODULE_DESCRIPTION("TI CPSW Port's PHY Interface Mode selection Driver");