From d7acb49aeeaef0a35b05869bd8345c4b8c7c7481 Mon Sep 17 00:00:00 2001 From: Jared McNeill Date: Thu, 3 Mar 2016 22:26:36 +0000 Subject: Add support for resetting the PHY via GPIO. Submitted by: Emmanuel Vadot Reviewed by: andrew, jmcneill Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D5505 --- sys/dev/dwc/if_dwc.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'sys/dev/dwc') 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 #include #include +#include #include #include #include @@ -70,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include #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); -- cgit v1.2.3