1215a0656SMarek Vasut // SPDX-License-Identifier: GPL-2.0+
2215a0656SMarek Vasut /*
3215a0656SMarek Vasut * Copyright (C) 2018 Marek Vasut <marex@denx.de>
4215a0656SMarek Vasut *
5215a0656SMarek Vasut * Altera SoCFPGA EMAC extras
6215a0656SMarek Vasut */
7215a0656SMarek Vasut
8215a0656SMarek Vasut #include <common.h>
9215a0656SMarek Vasut #include <asm/io.h>
10215a0656SMarek Vasut #include <dm.h>
11215a0656SMarek Vasut #include <clk.h>
12215a0656SMarek Vasut #include <phy.h>
13215a0656SMarek Vasut #include <regmap.h>
14215a0656SMarek Vasut #include <reset.h>
15215a0656SMarek Vasut #include <syscon.h>
16215a0656SMarek Vasut #include "designware.h"
17215a0656SMarek Vasut
18215a0656SMarek Vasut #include <asm/arch/system_manager.h>
19215a0656SMarek Vasut
20215a0656SMarek Vasut struct dwmac_socfpga_platdata {
21215a0656SMarek Vasut struct dw_eth_pdata dw_eth_pdata;
22215a0656SMarek Vasut void *phy_intf;
23*4f1267ceSSimon Goldschmidt u32 reg_shift;
24215a0656SMarek Vasut };
25215a0656SMarek Vasut
dwmac_socfpga_ofdata_to_platdata(struct udevice * dev)26215a0656SMarek Vasut static int dwmac_socfpga_ofdata_to_platdata(struct udevice *dev)
27215a0656SMarek Vasut {
28215a0656SMarek Vasut struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev);
29215a0656SMarek Vasut struct regmap *regmap;
30215a0656SMarek Vasut struct ofnode_phandle_args args;
31215a0656SMarek Vasut void *range;
32215a0656SMarek Vasut int ret;
33215a0656SMarek Vasut
34215a0656SMarek Vasut ret = dev_read_phandle_with_args(dev, "altr,sysmgr-syscon", NULL,
35215a0656SMarek Vasut 2, 0, &args);
36215a0656SMarek Vasut if (ret) {
37215a0656SMarek Vasut dev_err(dev, "Failed to get syscon: %d\n", ret);
38215a0656SMarek Vasut return ret;
39215a0656SMarek Vasut }
40215a0656SMarek Vasut
41215a0656SMarek Vasut if (args.args_count != 2) {
42215a0656SMarek Vasut dev_err(dev, "Invalid number of syscon args\n");
43215a0656SMarek Vasut return -EINVAL;
44215a0656SMarek Vasut }
45215a0656SMarek Vasut
46215a0656SMarek Vasut regmap = syscon_node_to_regmap(args.node);
47215a0656SMarek Vasut if (IS_ERR(regmap)) {
48215a0656SMarek Vasut ret = PTR_ERR(regmap);
49215a0656SMarek Vasut dev_err(dev, "Failed to get regmap: %d\n", ret);
50215a0656SMarek Vasut return ret;
51215a0656SMarek Vasut }
52215a0656SMarek Vasut
53215a0656SMarek Vasut range = regmap_get_range(regmap, 0);
54215a0656SMarek Vasut if (!range) {
55215a0656SMarek Vasut dev_err(dev, "Failed to get regmap range\n");
56215a0656SMarek Vasut return -ENOMEM;
57215a0656SMarek Vasut }
58215a0656SMarek Vasut
59215a0656SMarek Vasut pdata->phy_intf = range + args.args[0];
60*4f1267ceSSimon Goldschmidt pdata->reg_shift = args.args[1];
61215a0656SMarek Vasut
62215a0656SMarek Vasut return designware_eth_ofdata_to_platdata(dev);
63215a0656SMarek Vasut }
64215a0656SMarek Vasut
dwmac_socfpga_probe(struct udevice * dev)65215a0656SMarek Vasut static int dwmac_socfpga_probe(struct udevice *dev)
66215a0656SMarek Vasut {
67215a0656SMarek Vasut struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev);
68215a0656SMarek Vasut struct eth_pdata *edata = &pdata->dw_eth_pdata.eth_pdata;
69215a0656SMarek Vasut struct reset_ctl_bulk reset_bulk;
70215a0656SMarek Vasut int ret;
71*4f1267ceSSimon Goldschmidt u32 modereg;
72*4f1267ceSSimon Goldschmidt u32 modemask;
73215a0656SMarek Vasut
74215a0656SMarek Vasut switch (edata->phy_interface) {
75215a0656SMarek Vasut case PHY_INTERFACE_MODE_MII:
76215a0656SMarek Vasut case PHY_INTERFACE_MODE_GMII:
77215a0656SMarek Vasut modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
78215a0656SMarek Vasut break;
79215a0656SMarek Vasut case PHY_INTERFACE_MODE_RMII:
80215a0656SMarek Vasut modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII;
81215a0656SMarek Vasut break;
82215a0656SMarek Vasut case PHY_INTERFACE_MODE_RGMII:
83215a0656SMarek Vasut modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
84215a0656SMarek Vasut break;
85215a0656SMarek Vasut default:
86215a0656SMarek Vasut dev_err(dev, "Unsupported PHY mode\n");
87215a0656SMarek Vasut return -EINVAL;
88215a0656SMarek Vasut }
89215a0656SMarek Vasut
90215a0656SMarek Vasut ret = reset_get_bulk(dev, &reset_bulk);
91215a0656SMarek Vasut if (ret) {
92215a0656SMarek Vasut dev_err(dev, "Failed to get reset: %d\n", ret);
93215a0656SMarek Vasut return ret;
94215a0656SMarek Vasut }
95215a0656SMarek Vasut
96215a0656SMarek Vasut reset_assert_bulk(&reset_bulk);
97215a0656SMarek Vasut
98*4f1267ceSSimon Goldschmidt modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << pdata->reg_shift;
99*4f1267ceSSimon Goldschmidt clrsetbits_le32(pdata->phy_intf, modemask,
100*4f1267ceSSimon Goldschmidt modereg << pdata->reg_shift);
101215a0656SMarek Vasut
102215a0656SMarek Vasut reset_release_bulk(&reset_bulk);
103215a0656SMarek Vasut
104215a0656SMarek Vasut return designware_eth_probe(dev);
105215a0656SMarek Vasut }
106215a0656SMarek Vasut
107215a0656SMarek Vasut static const struct udevice_id dwmac_socfpga_ids[] = {
108215a0656SMarek Vasut { .compatible = "altr,socfpga-stmmac" },
109215a0656SMarek Vasut { }
110215a0656SMarek Vasut };
111215a0656SMarek Vasut
112215a0656SMarek Vasut U_BOOT_DRIVER(dwmac_socfpga) = {
113215a0656SMarek Vasut .name = "dwmac_socfpga",
114215a0656SMarek Vasut .id = UCLASS_ETH,
115215a0656SMarek Vasut .of_match = dwmac_socfpga_ids,
116215a0656SMarek Vasut .ofdata_to_platdata = dwmac_socfpga_ofdata_to_platdata,
117215a0656SMarek Vasut .probe = dwmac_socfpga_probe,
118215a0656SMarek Vasut .ops = &designware_eth_ops,
119215a0656SMarek Vasut .priv_auto_alloc_size = sizeof(struct dw_eth_dev),
120215a0656SMarek Vasut .platdata_auto_alloc_size = sizeof(struct dwmac_socfpga_platdata),
121215a0656SMarek Vasut .flags = DM_FLAG_ALLOC_PRIV_DMA,
122215a0656SMarek Vasut };
123