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
This commit is contained in:
parent
7bf46e12dd
commit
d7acb49aee
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=296365
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user