aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJared McNeill <jmcneill@FreeBSD.org>2016-03-03 22:26:36 +0000
committerJared McNeill <jmcneill@FreeBSD.org>2016-03-03 22:26:36 +0000
commitd7acb49aeeaef0a35b05869bd8345c4b8c7c7481 (patch)
tree530338470716c942e7b8e6c8ff0501431fbe5547 /sys/dev
parent7bf46e12dd64359895e2e94a34fbe9eb2c970241 (diff)
downloadsrc-d7acb49aeeaef0a35b05869bd8345c4b8c7c7481.tar.gz
src-d7acb49aeeaef0a35b05869bd8345c4b8c7c7481.zip
Add support for resetting the PHY via GPIO.
Submitted by: Emmanuel Vadot <manu@bidouilliste.com> Reviewed by: andrew, jmcneill Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D5505
Notes
Notes: svn path=/head/; revision=296365
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/dwc/if_dwc.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/sys/dev/dwc/if_dwc.c b/sys/dev/dwc/if_dwc.c
index e25d7f5a3d20..f0548d8d2c0b 100644
--- a/sys/dev/dwc/if_dwc.c
+++ b/sys/dev/dwc/if_dwc.c
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
+#include <sys/gpio.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
@@ -70,6 +71,7 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include "if_dwc_if.h"
+#include "gpio_if.h"
#include "miibus_if.h"
#define READ4(_sc, _reg) \
@@ -1010,6 +1012,62 @@ dwc_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr)
return (0);
}
+#define GPIO_ACTIVE_LOW 1
+
+static int
+dwc_reset(device_t dev)
+{
+ pcell_t gpio_prop[4];
+ pcell_t delay_prop[3];
+ phandle_t node, gpio_node;
+ device_t gpio;
+ uint32_t pin, flags;
+ uint32_t pin_value;
+
+ node = ofw_bus_get_node(dev);
+ if (OF_getencprop(node, "snps,reset-gpio",
+ gpio_prop, sizeof(gpio_prop)) <= 0)
+ return (0);
+
+ if (OF_getencprop(node, "snps,reset-delays-us",
+ delay_prop, sizeof(delay_prop)) <= 0) {
+ device_printf(dev,
+ "Wrong property for snps,reset-delays-us");
+ return (ENXIO);
+ }
+
+ gpio_node = OF_node_from_xref(gpio_prop[0]);
+ if ((gpio = OF_device_from_xref(gpio_prop[0])) == NULL) {
+ device_printf(dev,
+ "Can't find gpio controller for phy reset\n");
+ return (ENXIO);
+ }
+
+ if (GPIO_MAP_GPIOS(gpio, node, gpio_node,
+ sizeof(gpio_prop) / sizeof(gpio_prop[0]) - 1,
+ gpio_prop + 1, &pin, &flags) != 0) {
+ device_printf(dev, "Can't map gpio for phy reset\n");
+ return (ENXIO);
+ }
+
+ pin_value = GPIO_PIN_LOW;
+ if (OF_hasprop(node, "snps,reset-active-low"))
+ pin_value = GPIO_PIN_HIGH;
+
+ if (flags & GPIO_ACTIVE_LOW)
+ pin_value = !pin_value;
+
+ GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT);
+ GPIO_PIN_SET(gpio, pin, pin_value);
+ DELAY(delay_prop[0]);
+ GPIO_PIN_SET(gpio, pin, !pin_value);
+ DELAY(delay_prop[1]);
+ GPIO_PIN_SET(gpio, pin, pin_value);
+ DELAY(delay_prop[2]);
+
+ return (0);
+}
+
static int
dwc_probe(device_t dev)
{
@@ -1058,6 +1116,12 @@ dwc_attach(device_t dev)
return (ENXIO);
}
+ /* Reset the PHY if needed */
+ if (dwc_reset(dev) != 0) {
+ device_printf(dev, "Can't reset the PHY\n");
+ return (ENXIO);
+ }
+
/* Reset */
reg = READ4(sc, BUS_MODE);
reg |= (BUS_MODE_SWR);