xref: /openbmc/linux/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
110145f7cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
22d1611afSAlexandru Gagniuc /*
32d1611afSAlexandru Gagniuc  * Adaptrum Anarion DWMAC glue layer
42d1611afSAlexandru Gagniuc  *
52d1611afSAlexandru Gagniuc  * Copyright (C) 2017, Adaptrum, Inc.
62d1611afSAlexandru Gagniuc  * (Written by Alexandru Gagniuc <alex.g at adaptrum.com> for Adaptrum, Inc.)
72d1611afSAlexandru Gagniuc  */
82d1611afSAlexandru Gagniuc 
92d1611afSAlexandru Gagniuc #include <linux/io.h>
102d1611afSAlexandru Gagniuc #include <linux/of.h>
112d1611afSAlexandru Gagniuc #include <linux/of_net.h>
122d1611afSAlexandru Gagniuc #include <linux/stmmac.h>
132d1611afSAlexandru Gagniuc 
142d1611afSAlexandru Gagniuc #include "stmmac.h"
152d1611afSAlexandru Gagniuc #include "stmmac_platform.h"
162d1611afSAlexandru Gagniuc 
172d1611afSAlexandru Gagniuc #define GMAC_RESET_CONTROL_REG		0
182d1611afSAlexandru Gagniuc #define GMAC_SW_CONFIG_REG		4
192d1611afSAlexandru Gagniuc #define  GMAC_CONFIG_INTF_SEL_MASK	(0x7 << 0)
202d1611afSAlexandru Gagniuc #define  GMAC_CONFIG_INTF_RGMII		(0x1 << 0)
212d1611afSAlexandru Gagniuc 
222d1611afSAlexandru Gagniuc struct anarion_gmac {
239f12541dSSimon Horman 	void __iomem *ctl_block;
242d1611afSAlexandru Gagniuc 	uint32_t phy_intf_sel;
252d1611afSAlexandru Gagniuc };
262d1611afSAlexandru Gagniuc 
gmac_read_reg(struct anarion_gmac * gmac,uint8_t reg)272d1611afSAlexandru Gagniuc static uint32_t gmac_read_reg(struct anarion_gmac *gmac, uint8_t reg)
282d1611afSAlexandru Gagniuc {
299f12541dSSimon Horman 	return readl(gmac->ctl_block + reg);
302d1611afSAlexandru Gagniuc };
312d1611afSAlexandru Gagniuc 
gmac_write_reg(struct anarion_gmac * gmac,uint8_t reg,uint32_t val)322d1611afSAlexandru Gagniuc static void gmac_write_reg(struct anarion_gmac *gmac, uint8_t reg, uint32_t val)
332d1611afSAlexandru Gagniuc {
349f12541dSSimon Horman 	writel(val, gmac->ctl_block + reg);
352d1611afSAlexandru Gagniuc }
362d1611afSAlexandru Gagniuc 
anarion_gmac_init(struct platform_device * pdev,void * priv)372d1611afSAlexandru Gagniuc static int anarion_gmac_init(struct platform_device *pdev, void *priv)
382d1611afSAlexandru Gagniuc {
392d1611afSAlexandru Gagniuc 	uint32_t sw_config;
402d1611afSAlexandru Gagniuc 	struct anarion_gmac *gmac = priv;
412d1611afSAlexandru Gagniuc 
422d1611afSAlexandru Gagniuc 	/* Reset logic, configure interface mode, then release reset. SIMPLE! */
432d1611afSAlexandru Gagniuc 	gmac_write_reg(gmac, GMAC_RESET_CONTROL_REG, 1);
442d1611afSAlexandru Gagniuc 
452d1611afSAlexandru Gagniuc 	sw_config = gmac_read_reg(gmac, GMAC_SW_CONFIG_REG);
462d1611afSAlexandru Gagniuc 	sw_config &= ~GMAC_CONFIG_INTF_SEL_MASK;
472d1611afSAlexandru Gagniuc 	sw_config |= (gmac->phy_intf_sel & GMAC_CONFIG_INTF_SEL_MASK);
482d1611afSAlexandru Gagniuc 	gmac_write_reg(gmac, GMAC_SW_CONFIG_REG, sw_config);
492d1611afSAlexandru Gagniuc 
502d1611afSAlexandru Gagniuc 	gmac_write_reg(gmac, GMAC_RESET_CONTROL_REG, 0);
512d1611afSAlexandru Gagniuc 
522d1611afSAlexandru Gagniuc 	return 0;
532d1611afSAlexandru Gagniuc }
542d1611afSAlexandru Gagniuc 
anarion_gmac_exit(struct platform_device * pdev,void * priv)552d1611afSAlexandru Gagniuc static void anarion_gmac_exit(struct platform_device *pdev, void *priv)
562d1611afSAlexandru Gagniuc {
572d1611afSAlexandru Gagniuc 	struct anarion_gmac *gmac = priv;
582d1611afSAlexandru Gagniuc 
592d1611afSAlexandru Gagniuc 	gmac_write_reg(gmac, GMAC_RESET_CONTROL_REG, 1);
602d1611afSAlexandru Gagniuc }
612d1611afSAlexandru Gagniuc 
anarion_config_dt(struct platform_device * pdev)622d1611afSAlexandru Gagniuc static struct anarion_gmac *anarion_config_dt(struct platform_device *pdev)
632d1611afSAlexandru Gagniuc {
642d1611afSAlexandru Gagniuc 	struct anarion_gmac *gmac;
650c65b2b9SAndrew Lunn 	phy_interface_t phy_mode;
660c65b2b9SAndrew Lunn 	void __iomem *ctl_block;
670c65b2b9SAndrew Lunn 	int err;
682d1611afSAlexandru Gagniuc 
69ad124aa3SYueHaibing 	ctl_block = devm_platform_ioremap_resource(pdev, 1);
702d1611afSAlexandru Gagniuc 	if (IS_ERR(ctl_block)) {
71*51fe084bSSimon Horman 		err = PTR_ERR(ctl_block);
72*51fe084bSSimon Horman 		dev_err(&pdev->dev, "Cannot get reset region (%d)!\n", err);
73*51fe084bSSimon Horman 		return ERR_PTR(err);
742d1611afSAlexandru Gagniuc 	}
752d1611afSAlexandru Gagniuc 
762d1611afSAlexandru Gagniuc 	gmac = devm_kzalloc(&pdev->dev, sizeof(*gmac), GFP_KERNEL);
772d1611afSAlexandru Gagniuc 	if (!gmac)
782d1611afSAlexandru Gagniuc 		return ERR_PTR(-ENOMEM);
792d1611afSAlexandru Gagniuc 
809f12541dSSimon Horman 	gmac->ctl_block = ctl_block;
812d1611afSAlexandru Gagniuc 
820c65b2b9SAndrew Lunn 	err = of_get_phy_mode(pdev->dev.of_node, &phy_mode);
830c65b2b9SAndrew Lunn 	if (err)
840c65b2b9SAndrew Lunn 		return ERR_PTR(err);
850c65b2b9SAndrew Lunn 
862d1611afSAlexandru Gagniuc 	switch (phy_mode) {
87df561f66SGustavo A. R. Silva 	case PHY_INTERFACE_MODE_RGMII:
88df561f66SGustavo A. R. Silva 		fallthrough;
89df561f66SGustavo A. R. Silva 	case PHY_INTERFACE_MODE_RGMII_ID:
90df561f66SGustavo A. R. Silva 	case PHY_INTERFACE_MODE_RGMII_RXID:
912d1611afSAlexandru Gagniuc 	case PHY_INTERFACE_MODE_RGMII_TXID:
922d1611afSAlexandru Gagniuc 		gmac->phy_intf_sel = GMAC_CONFIG_INTF_RGMII;
932d1611afSAlexandru Gagniuc 		break;
942d1611afSAlexandru Gagniuc 	default:
952d1611afSAlexandru Gagniuc 		dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n",
962d1611afSAlexandru Gagniuc 			phy_mode);
972d1611afSAlexandru Gagniuc 		return ERR_PTR(-ENOTSUPP);
982d1611afSAlexandru Gagniuc 	}
992d1611afSAlexandru Gagniuc 
1002d1611afSAlexandru Gagniuc 	return gmac;
1012d1611afSAlexandru Gagniuc }
1022d1611afSAlexandru Gagniuc 
anarion_dwmac_probe(struct platform_device * pdev)1032d1611afSAlexandru Gagniuc static int anarion_dwmac_probe(struct platform_device *pdev)
1042d1611afSAlexandru Gagniuc {
1052d1611afSAlexandru Gagniuc 	int ret;
1062d1611afSAlexandru Gagniuc 	struct anarion_gmac *gmac;
1072d1611afSAlexandru Gagniuc 	struct plat_stmmacenet_data *plat_dat;
1082d1611afSAlexandru Gagniuc 	struct stmmac_resources stmmac_res;
1092d1611afSAlexandru Gagniuc 
1102d1611afSAlexandru Gagniuc 	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
1112d1611afSAlexandru Gagniuc 	if (ret)
1122d1611afSAlexandru Gagniuc 		return ret;
1132d1611afSAlexandru Gagniuc 
1142d1611afSAlexandru Gagniuc 	gmac = anarion_config_dt(pdev);
1152d1611afSAlexandru Gagniuc 	if (IS_ERR(gmac))
1162d1611afSAlexandru Gagniuc 		return PTR_ERR(gmac);
1172d1611afSAlexandru Gagniuc 
11883216e39SMichael Walle 	plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
1192d1611afSAlexandru Gagniuc 	if (IS_ERR(plat_dat))
1202d1611afSAlexandru Gagniuc 		return PTR_ERR(plat_dat);
1212d1611afSAlexandru Gagniuc 
1222d1611afSAlexandru Gagniuc 	plat_dat->init = anarion_gmac_init;
1232d1611afSAlexandru Gagniuc 	plat_dat->exit = anarion_gmac_exit;
1242d1611afSAlexandru Gagniuc 	anarion_gmac_init(pdev, gmac);
1252d1611afSAlexandru Gagniuc 	plat_dat->bsp_priv = gmac;
1262d1611afSAlexandru Gagniuc 
1272d1611afSAlexandru Gagniuc 	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
1282d1611afSAlexandru Gagniuc 	if (ret) {
1292d1611afSAlexandru Gagniuc 		stmmac_remove_config_dt(pdev, plat_dat);
1302d1611afSAlexandru Gagniuc 		return ret;
1312d1611afSAlexandru Gagniuc 	}
1322d1611afSAlexandru Gagniuc 
1332d1611afSAlexandru Gagniuc 	return 0;
1342d1611afSAlexandru Gagniuc }
1352d1611afSAlexandru Gagniuc 
1362d1611afSAlexandru Gagniuc static const struct of_device_id anarion_dwmac_match[] = {
1372d1611afSAlexandru Gagniuc 	{ .compatible = "adaptrum,anarion-gmac" },
1382d1611afSAlexandru Gagniuc 	{ }
1392d1611afSAlexandru Gagniuc };
1402d1611afSAlexandru Gagniuc MODULE_DEVICE_TABLE(of, anarion_dwmac_match);
1412d1611afSAlexandru Gagniuc 
1422d1611afSAlexandru Gagniuc static struct platform_driver anarion_dwmac_driver = {
1432d1611afSAlexandru Gagniuc 	.probe  = anarion_dwmac_probe,
1442d1611afSAlexandru Gagniuc 	.remove_new = stmmac_pltfr_remove,
1452d1611afSAlexandru Gagniuc 	.driver = {
1462d1611afSAlexandru Gagniuc 		.name           = "anarion-dwmac",
1472d1611afSAlexandru Gagniuc 		.pm		= &stmmac_pltfr_pm_ops,
1482d1611afSAlexandru Gagniuc 		.of_match_table = anarion_dwmac_match,
1492d1611afSAlexandru Gagniuc 	},
1502d1611afSAlexandru Gagniuc };
1512d1611afSAlexandru Gagniuc module_platform_driver(anarion_dwmac_driver);
1522d1611afSAlexandru Gagniuc 
1532d1611afSAlexandru Gagniuc MODULE_DESCRIPTION("Adaptrum Anarion DWMAC specific glue layer");
1542d1611afSAlexandru Gagniuc MODULE_AUTHOR("Alexandru Gagniuc <mr.nuke.me@gmail.com>");
1552d1611afSAlexandru Gagniuc MODULE_LICENSE("GPL v2");
156