aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
diff options
context:
space:
mode:
authorJonas Gorski <jonas.gorski@gmail.com>2017-02-09 21:20:41 +0100
committerJonas Gorski <jonas.gorski@gmail.com>2017-06-10 12:40:38 +0200
commit5df15c06ccd105a19431bc32bd1d158b3ff3325e (patch)
treed47eee3a3f9f18a36fe9c5fe6913edfe9e4760a2 /target/linux/generic/files/drivers/net/phy/b53/b53_common.c
parent9ceeaf4c6cac6e5ff5a5225a5c9d13ba63d9c478 (diff)
downloadupstream-5df15c06ccd105a19431bc32bd1d158b3ff3325e.tar.gz
upstream-5df15c06ccd105a19431bc32bd1d158b3ff3325e.tar.bz2
upstream-5df15c06ccd105a19431bc32bd1d158b3ff3325e.zip
b53: allow configuration through device tree
Add support for the same binding as upstream b53 to allow an easy switch. Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
Diffstat (limited to 'target/linux/generic/files/drivers/net/phy/b53/b53_common.c')
-rw-r--r--target/linux/generic/files/drivers/net/phy/b53/b53_common.c177
1 files changed, 158 insertions, 19 deletions
diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
index b884010d28..482966a909 100644
--- a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
+++ b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
@@ -24,6 +24,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/switch.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
#include <linux/platform_data/b53.h>
#include "b53_regs.h"
@@ -478,35 +480,88 @@ static void b53_switch_reset_gpio(struct b53_device *dev)
dev->current_page = 0xff;
}
-static int b53_switch_reset(struct b53_device *dev)
+static int b53_configure_ports_of(struct b53_device *dev)
{
- u8 cpu_port = dev->sw_dev.cpu_port;
- u8 mgmt;
+ struct device_node *dn, *pn;
+ u32 port_num;
- b53_switch_reset_gpio(dev);
+ dn = of_get_child_by_name(dev_of_node(dev->dev), "ports");
- if (is539x(dev)) {
- b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83);
- b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00);
- }
+ for_each_available_child_of_node(dn, pn) {
+ struct device_node *fixed_link;
- b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+ if (of_property_read_u32(pn, "reg", &port_num))
+ continue;
- if (!(mgmt & SM_SW_FWD_EN)) {
- mgmt &= ~SM_SW_FWD_MODE;
- mgmt |= SM_SW_FWD_EN;
+ if (port_num > B53_CPU_PORT)
+ continue;
- b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
- b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+ fixed_link = of_get_child_by_name(pn, "fixed-link");
+ if (fixed_link) {
+ u32 spd;
+ u8 po = GMII_PO_LINK;
+ int mode = of_get_phy_mode(pn);
+
+ if (!of_property_read_u32(fixed_link, "speed", &spd)) {
+ switch (spd) {
+ case 10:
+ po |= GMII_PO_SPEED_10M;
+ break;
+ case 100:
+ po |= GMII_PO_SPEED_100M;
+ break;
+ case 2000:
+ if (is_imp_port(dev, port_num))
+ po |= PORT_OVERRIDE_SPEED_2000M;
+ else
+ po |= GMII_PO_SPEED_2000M;
+ /* fall through */
+ case 1000:
+ po |= GMII_PO_SPEED_1000M;
+ break;
+ }
+ }
- if (!(mgmt & SM_SW_FWD_EN)) {
- pr_err("Failed to enable switch!\n");
- return -EINVAL;
+ if (of_property_read_bool(fixed_link, "full-duplex"))
+ po |= PORT_OVERRIDE_FULL_DUPLEX;
+ if (of_property_read_bool(fixed_link, "pause"))
+ po |= GMII_PO_RX_FLOW;
+ if (of_property_read_bool(fixed_link, "asym-pause"))
+ po |= GMII_PO_TX_FLOW;
+
+ if (is_imp_port(dev, port_num)) {
+ po |= PORT_OVERRIDE_EN;
+
+ if (is5325(dev) &&
+ mode == PHY_INTERFACE_MODE_REVMII)
+ po |= PORT_OVERRIDE_RV_MII_25;
+
+ b53_write8(dev, B53_CTRL_PAGE,
+ B53_PORT_OVERRIDE_CTRL, po);
+
+ if (is5325(dev) &&
+ mode == PHY_INTERFACE_MODE_REVMII) {
+ b53_read8(dev, B53_CTRL_PAGE,
+ B53_PORT_OVERRIDE_CTRL, &po);
+ if (!(po & PORT_OVERRIDE_RV_MII_25))
+ pr_err("Failed to enable reverse MII mode\n");
+ return -EINVAL;
+ }
+ } else {
+ po |= GMII_PO_EN;
+ b53_write8(dev, B53_CTRL_PAGE,
+ B53_GMII_PORT_OVERRIDE_CTRL(port_num),
+ po);
+ }
}
}
- /* enable all ports */
- b53_enable_ports(dev);
+ return 0;
+}
+
+static int b53_configure_ports(struct b53_device *dev)
+{
+ u8 cpu_port = dev->sw_dev.cpu_port;
/* configure MII port if necessary */
if (is5325(dev)) {
@@ -576,6 +631,47 @@ static int b53_switch_reset(struct b53_device *dev)
}
}
+ return 0;
+}
+
+static int b53_switch_reset(struct b53_device *dev)
+{
+ int ret = 0;
+ u8 mgmt;
+
+ b53_switch_reset_gpio(dev);
+
+ if (is539x(dev)) {
+ b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83);
+ b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00);
+ }
+
+ b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+ if (!(mgmt & SM_SW_FWD_EN)) {
+ mgmt &= ~SM_SW_FWD_MODE;
+ mgmt |= SM_SW_FWD_EN;
+
+ b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
+ b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
+
+ if (!(mgmt & SM_SW_FWD_EN)) {
+ pr_err("Failed to enable switch!\n");
+ return -EINVAL;
+ }
+ }
+
+ /* enable all ports */
+ b53_enable_ports(dev);
+
+ if (dev->dev->of_node)
+ ret = b53_configure_ports_of(dev);
+ else
+ ret = b53_configure_ports(dev);
+
+ if (ret)
+ return ret;
+
b53_enable_mib(dev);
return b53_flush_arl(dev);
@@ -1320,6 +1416,43 @@ static const struct b53_chip_data b53_switch_chips[] = {
},
};
+static int b53_switch_init_of(struct b53_device *dev)
+{
+ struct device_node *dn, *pn;
+ const char *alias;
+ u32 port_num;
+ u16 ports = 0;
+
+ dn = of_get_child_by_name(dev_of_node(dev->dev), "ports");
+ if (!dn)
+ return -EINVAL;
+
+ for_each_available_child_of_node(dn, pn) {
+ const char *label;
+ int len;
+
+ if (of_property_read_u32(pn, "reg", &port_num))
+ continue;
+
+ if (port_num > B53_CPU_PORT)
+ continue;
+
+ ports |= BIT(port_num);
+
+ label = of_get_property(pn, "label", &len);
+ if (label && !strcmp(label, "cpu"))
+ dev->sw_dev.cpu_port = port_num;
+ }
+
+ dev->enabled_ports = ports;
+
+ if (!of_property_read_string(dev_of_node(dev->dev), "lede,alias",
+ &alias))
+ dev->sw_dev.alias = devm_kstrdup(dev->dev, alias, GFP_KERNEL);
+
+ return 0;
+}
+
static int b53_switch_init(struct b53_device *dev)
{
struct switch_dev *sw_dev = &dev->sw_dev;
@@ -1383,6 +1516,12 @@ static int b53_switch_init(struct b53_device *dev)
sw_dev->cpu_port = 5;
}
+ if (dev_of_node(dev->dev)) {
+ ret = b53_switch_init_of(dev);
+ if (ret)
+ return ret;
+ }
+
dev->enabled_ports |= BIT(sw_dev->cpu_port);
sw_dev->ports = fls(dev->enabled_ports);