1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Adaptrum Anarion DWMAC glue layer
5 * Copyright (C) 2017, Adaptrum, Inc.
6 * (Written by Alexandru Gagniuc <alex.g at adaptrum.com> for Adaptrum, Inc.)
11 #include <linux/of_net.h>
12 #include <linux/stmmac.h>
15 #include "stmmac_platform.h"
17 #define GMAC_RESET_CONTROL_REG 0
18 #define GMAC_SW_CONFIG_REG 4
19 #define GMAC_CONFIG_INTF_SEL_MASK (0x7 << 0)
20 #define GMAC_CONFIG_INTF_RGMII (0x1 << 0)
24 uint32_t phy_intf_sel
;
27 static uint32_t gmac_read_reg(struct anarion_gmac
*gmac
, uint8_t reg
)
29 return readl((void *)(gmac
->ctl_block
+ reg
));
32 static void gmac_write_reg(struct anarion_gmac
*gmac
, uint8_t reg
, uint32_t val
)
34 writel(val
, (void *)(gmac
->ctl_block
+ reg
));
37 static int anarion_gmac_init(struct platform_device
*pdev
, void *priv
)
40 struct anarion_gmac
*gmac
= priv
;
42 /* Reset logic, configure interface mode, then release reset. SIMPLE! */
43 gmac_write_reg(gmac
, GMAC_RESET_CONTROL_REG
, 1);
45 sw_config
= gmac_read_reg(gmac
, GMAC_SW_CONFIG_REG
);
46 sw_config
&= ~GMAC_CONFIG_INTF_SEL_MASK
;
47 sw_config
|= (gmac
->phy_intf_sel
& GMAC_CONFIG_INTF_SEL_MASK
);
48 gmac_write_reg(gmac
, GMAC_SW_CONFIG_REG
, sw_config
);
50 gmac_write_reg(gmac
, GMAC_RESET_CONTROL_REG
, 0);
55 static void anarion_gmac_exit(struct platform_device
*pdev
, void *priv
)
57 struct anarion_gmac
*gmac
= priv
;
59 gmac_write_reg(gmac
, GMAC_RESET_CONTROL_REG
, 1);
62 static struct anarion_gmac
*anarion_config_dt(struct platform_device
*pdev
)
64 struct anarion_gmac
*gmac
;
65 phy_interface_t phy_mode
;
66 void __iomem
*ctl_block
;
69 ctl_block
= devm_platform_ioremap_resource(pdev
, 1);
70 if (IS_ERR(ctl_block
)) {
71 dev_err(&pdev
->dev
, "Cannot get reset region (%ld)!\n",
76 gmac
= devm_kzalloc(&pdev
->dev
, sizeof(*gmac
), GFP_KERNEL
);
78 return ERR_PTR(-ENOMEM
);
80 gmac
->ctl_block
= (uintptr_t)ctl_block
;
82 err
= of_get_phy_mode(pdev
->dev
.of_node
, &phy_mode
);
87 case PHY_INTERFACE_MODE_RGMII
: /* Fall through */
88 case PHY_INTERFACE_MODE_RGMII_ID
/* Fall through */:
89 case PHY_INTERFACE_MODE_RGMII_RXID
: /* Fall through */
90 case PHY_INTERFACE_MODE_RGMII_TXID
:
91 gmac
->phy_intf_sel
= GMAC_CONFIG_INTF_RGMII
;
94 dev_err(&pdev
->dev
, "Unsupported phy-mode (%d)\n",
96 return ERR_PTR(-ENOTSUPP
);
102 static int anarion_dwmac_probe(struct platform_device
*pdev
)
105 struct anarion_gmac
*gmac
;
106 struct plat_stmmacenet_data
*plat_dat
;
107 struct stmmac_resources stmmac_res
;
109 ret
= stmmac_get_platform_resources(pdev
, &stmmac_res
);
113 gmac
= anarion_config_dt(pdev
);
115 return PTR_ERR(gmac
);
117 plat_dat
= stmmac_probe_config_dt(pdev
, &stmmac_res
.mac
);
118 if (IS_ERR(plat_dat
))
119 return PTR_ERR(plat_dat
);
121 plat_dat
->init
= anarion_gmac_init
;
122 plat_dat
->exit
= anarion_gmac_exit
;
123 anarion_gmac_init(pdev
, gmac
);
124 plat_dat
->bsp_priv
= gmac
;
126 ret
= stmmac_dvr_probe(&pdev
->dev
, plat_dat
, &stmmac_res
);
128 stmmac_remove_config_dt(pdev
, plat_dat
);
135 static const struct of_device_id anarion_dwmac_match
[] = {
136 { .compatible
= "adaptrum,anarion-gmac" },
139 MODULE_DEVICE_TABLE(of
, anarion_dwmac_match
);
141 static struct platform_driver anarion_dwmac_driver
= {
142 .probe
= anarion_dwmac_probe
,
143 .remove
= stmmac_pltfr_remove
,
145 .name
= "anarion-dwmac",
146 .pm
= &stmmac_pltfr_pm_ops
,
147 .of_match_table
= anarion_dwmac_match
,
150 module_platform_driver(anarion_dwmac_driver
);
152 MODULE_DESCRIPTION("Adaptrum Anarion DWMAC specific glue layer");
153 MODULE_AUTHOR("Alexandru Gagniuc <mr.nuke.me@gmail.com>");
154 MODULE_LICENSE("GPL v2");