aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_gmac.c
blob: 55a8f57f15557edd9a82aba9020f28bf325efa51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
 *  Atheros AR71xx built-in ethernet mac driver
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License version 2 as published
 *  by the Free Software Foundation.
 */

#include <linux/sizes.h>
#include <linux/of_address.h>
#include "ag71xx.h"

static void ag71xx_of_set(struct device_node *np, const char *prop,
			  u32 *reg, u32 shift, u32 mask)
{
	u32 val;

	if (of_property_read_u32(np, prop, &val))
		return;

	*reg &= ~(mask << shift);
	*reg |= ((val & mask) << shift);
}

static void ag71xx_of_bit(struct device_node *np, const char *prop,
			  u32 *reg, u32 mask)
{
	u32 val;

	if (of_property_read_u32(np, prop, &val))
		return;

	if (val)
		*reg |= mask;
	else
		*reg &= ~mask;
}

static void ag71xx_setup_gmac_933x(struct device_node *np, void __iomem *base)
{
	u32 val = __raw_readl(base + AR933X_GMAC_REG_ETH_CFG);

	ag71xx_of_bit(np, "switch-phy-swap", &val, AR933X_ETH_CFG_SW_PHY_SWAP);
	ag71xx_of_bit(np, "switch-phy-addr-swap", &val,
		AR933X_ETH_CFG_SW_PHY_ADDR_SWAP);

	__raw_writel(val, base + AR933X_GMAC_REG_ETH_CFG);
}

static void ag71xx_setup_gmac_934x(struct device_node *np, void __iomem *base)
{
	u32 val = __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);

	ag71xx_of_bit(np, "rgmii-gmac0", &val, AR934X_ETH_CFG_RGMII_GMAC0);
	ag71xx_of_bit(np, "mii-gmac0", &val, AR934X_ETH_CFG_MII_GMAC0);
	ag71xx_of_bit(np, "gmii-gmac0", &val, AR934X_ETH_CFG_GMII_GMAC0);
	ag71xx_of_bit(np, "switch-phy-swap", &val, AR934X_ETH_CFG_SW_PHY_SWAP);
	ag71xx_of_bit(np, "switch-only-mode", &val,
		AR934X_ETH_CFG_SW_ONLY_MODE);

	__raw_writel(val, base + AR934X_GMAC_REG_ETH_CFG);
}

static void ag71xx_setup_gmac_955x(struct device_node *np, void __iomem *base)
{
	u32 val = __raw_readl(base + QCA955X_GMAC_REG_ETH_CFG);

	ag71xx_of_bit(np, "rgmii-enabled", &val, QCA955X_ETH_CFG_RGMII_EN);
	ag71xx_of_bit(np, "ge0-sgmii", &val, QCA955X_ETH_CFG_GE0_SGMII);
	ag71xx_of_set(np, "txen-delay", &val, QCA955X_ETH_CFG_TXE_DELAY_SHIFT, 0x3);
	ag71xx_of_set(np, "txd-delay", &val, QCA955X_ETH_CFG_TXD_DELAY_SHIFT, 0x3);
	ag71xx_of_set(np, "rxdv-delay", &val, QCA955X_ETH_CFG_RDV_DELAY_SHIFT, 0x3);
	ag71xx_of_set(np, "rxd-delay", &val, QCA955X_ETH_CFG_RXD_DELAY_SHIFT, 0x3);

	__raw_writel(val, base + QCA955X_GMAC_REG_ETH_CFG);
}

int ag71xx_setup_gmac(struct device_node *np)
{
	struct device_node *np_dev;
	void __iomem *base;
	int err = 0;

	np = of_get_child_by_name(np, "gmac-config");
	if (!np)
		return 0;

	np_dev = of_parse_phandle(np, "device", 0);
	if (!np_dev)
		goto out;

	base = of_iomap(np_dev, 0);
	if (!base) {
		pr_err("%pOF: can't map GMAC registers\n", np_dev);
		err = -ENOMEM;
		goto err_iomap;
	}

	if (of_device_is_compatible(np_dev, "qca,ar9330-gmac"))
		ag71xx_setup_gmac_933x(np, base);
	else if (of_device_is_compatible(np_dev, "qca,ar9340-gmac"))
		ag71xx_setup_gmac_934x(np, base);
	else if (of_device_is_compatible(np_dev, "qca,qca9550-gmac"))
		ag71xx_setup_gmac_955x(np, base);

	iounmap(base);

err_iomap:
	of_node_put(np_dev);
out:
	of_node_put(np);
	return err;
}