Improve Rockchip's integration of if_dwc
- Do not rely on U-Boot for clocks configuration, enable and set frequencies in the driver's attach method. - Adjust MAC settings according to detected linespeed on RK3399 and RK3328. - Add support for RMII PHY mode on RK3328. Reviewed by: manu Differential Revision: https://reviews.freebsd.org/D26006
This commit is contained in:
parent
25e42ee217
commit
824cfb4729
@ -23,7 +23,7 @@
|
|||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
@ -33,94 +33,347 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/bus.h>
|
#include <sys/bus.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
#include <sys/module.h>
|
#include <sys/module.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include <machine/bus.h>
|
#include <machine/bus.h>
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_media.h>
|
||||||
|
|
||||||
#include <dev/dwc/if_dwc.h>
|
#include <dev/dwc/if_dwc.h>
|
||||||
#include <dev/dwc/if_dwcvar.h>
|
#include <dev/dwc/if_dwcvar.h>
|
||||||
#include <dev/ofw/ofw_bus.h>
|
#include <dev/ofw/ofw_bus.h>
|
||||||
#include <dev/ofw/ofw_bus_subr.h>
|
#include <dev/ofw/ofw_bus_subr.h>
|
||||||
|
|
||||||
#include <dev/extres/clk/clk.h>
|
#include <dev/extres/clk/clk.h>
|
||||||
|
#include <dev/extres/hwreset/hwreset.h>
|
||||||
#include <dev/extres/regulator/regulator.h>
|
#include <dev/extres/regulator/regulator.h>
|
||||||
|
|
||||||
#include <dev/extres/syscon/syscon.h>
|
#include <dev/extres/syscon/syscon.h>
|
||||||
|
|
||||||
|
#include "if_dwc_if.h"
|
||||||
#include "syscon_if.h"
|
#include "syscon_if.h"
|
||||||
|
|
||||||
#include "if_dwc_if.h"
|
|
||||||
|
|
||||||
#define RK3328_GRF_MAC_CON0 0x0900
|
#define RK3328_GRF_MAC_CON0 0x0900
|
||||||
#define RK3328_GRF_MAC_CON0_TX_MASK 0x7F
|
#define MAC_CON0_GMAC2IO_TX_DL_CFG_MASK 0x7F
|
||||||
#define RK3328_GRF_MAC_CON0_TX_SHIFT 0
|
#define MAC_CON0_GMAC2IO_TX_DL_CFG_SHIFT 0
|
||||||
#define RK3328_GRF_MAC_CON0_RX_MASK 0x7F
|
#define MAC_CON0_GMAC2IO_RX_DL_CFG_MASK 0x7F
|
||||||
#define RK3328_GRF_MAC_CON0_RX_SHIFT 7
|
#define MAC_CON0_GMAC2IO_RX_DL_CFG_SHIFT 7
|
||||||
|
|
||||||
#define RK3328_GRF_MAC_CON1 0x0904
|
#define RK3328_GRF_MAC_CON1 0x0904
|
||||||
#define RK3328_GRF_MAC_CON1_RX_ENA (1 << 1)
|
#define MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA (1 << 0)
|
||||||
#define RK3328_GRF_MAC_CON1_TX_ENA (1 << 0)
|
#define MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA (1 << 1)
|
||||||
|
#define MAC_CON1_GMAC2IO_GMII_CLK_SEL_MASK (3 << 11)
|
||||||
|
#define MAC_CON1_GMAC2IO_GMII_CLK_SEL_125 (0 << 11)
|
||||||
|
#define MAC_CON1_GMAC2IO_GMII_CLK_SEL_25 (3 << 11)
|
||||||
|
#define MAC_CON1_GMAC2IO_GMII_CLK_SEL_2_5 (2 << 11)
|
||||||
|
#define MAC_CON1_GMAC2IO_RMII_MODE_MASK (1 << 9)
|
||||||
|
#define MAC_CON1_GMAC2IO_RMII_MODE (1 << 9)
|
||||||
|
#define MAC_CON1_GMAC2IO_INTF_SEL_MASK (7 << 4)
|
||||||
|
#define MAC_CON1_GMAC2IO_INTF_RMII (4 << 4)
|
||||||
|
#define MAC_CON1_GMAC2IO_INTF_RGMII (1 << 4)
|
||||||
|
#define MAC_CON1_GMAC2IO_RMII_CLK_SEL_MASK (1 << 7)
|
||||||
|
#define MAC_CON1_GMAC2IO_RMII_CLK_SEL_25 (1 << 7)
|
||||||
|
#define MAC_CON1_GMAC2IO_RMII_CLK_SEL_2_5 (0 << 7)
|
||||||
|
#define MAC_CON1_GMAC2IO_MAC_SPEED_MASK (1 << 2)
|
||||||
|
#define MAC_CON1_GMAC2IO_MAC_SPEED_100 (1 << 2)
|
||||||
|
#define MAC_CON1_GMAC2IO_MAC_SPEED_10 (0 << 2)
|
||||||
#define RK3328_GRF_MAC_CON2 0x0908
|
#define RK3328_GRF_MAC_CON2 0x0908
|
||||||
#define RK3328_GRF_MACPHY_CON0 0x0B00
|
#define RK3328_GRF_MACPHY_CON0 0x0B00
|
||||||
|
#define MACPHY_CON0_CLK_50M_MASK (1 << 14)
|
||||||
|
#define MACPHY_CON0_CLK_50M (1 << 14)
|
||||||
|
#define MACPHY_CON0_RMII_MODE_MASK (3 << 6)
|
||||||
|
#define MACPHY_CON0_RMII_MODE (1 << 6)
|
||||||
#define RK3328_GRF_MACPHY_CON1 0x0B04
|
#define RK3328_GRF_MACPHY_CON1 0x0B04
|
||||||
|
#define MACPHY_CON1_RMII_MODE_MASK (1 << 9)
|
||||||
|
#define MACPHY_CON1_RMII_MODE (1 << 9)
|
||||||
#define RK3328_GRF_MACPHY_CON2 0x0B08
|
#define RK3328_GRF_MACPHY_CON2 0x0B08
|
||||||
#define RK3328_GRF_MACPHY_CON3 0x0B0C
|
#define RK3328_GRF_MACPHY_CON3 0x0B0C
|
||||||
#define RK3328_GRF_MACPHY_STATUS 0x0B10
|
#define RK3328_GRF_MACPHY_STATUS 0x0B10
|
||||||
|
|
||||||
|
#define RK3399_GRF_SOC_CON5 0xc214
|
||||||
|
#define SOC_CON5_GMAC_CLK_SEL_MASK (3 << 4)
|
||||||
|
#define SOC_CON5_GMAC_CLK_SEL_125 (0 << 4)
|
||||||
|
#define SOC_CON5_GMAC_CLK_SEL_25 (3 << 4)
|
||||||
|
#define SOC_CON5_GMAC_CLK_SEL_2_5 (2 << 4)
|
||||||
|
#define RK3399_GRF_SOC_CON6 0xc218
|
||||||
|
#define SOC_CON6_GMAC_TXCLK_DLY_ENA (1 << 7)
|
||||||
|
#define SOC_CON6_TX_DL_CFG_MASK 0x7F
|
||||||
|
#define SOC_CON6_TX_DL_CFG_SHIFT 0
|
||||||
|
#define SOC_CON6_RX_DL_CFG_MASK 0x7F
|
||||||
|
#define SOC_CON6_GMAC_RXCLK_DLY_ENA (1 << 15)
|
||||||
|
#define SOC_CON6_RX_DL_CFG_SHIFT 8
|
||||||
|
|
||||||
|
struct if_dwc_rk_softc;
|
||||||
|
|
||||||
|
typedef void (*if_dwc_rk_set_delaysfn_t)(struct if_dwc_rk_softc *);
|
||||||
|
typedef int (*if_dwc_rk_set_speedfn_t)(struct if_dwc_rk_softc *, int);
|
||||||
|
typedef void (*if_dwc_rk_set_phy_modefn_t)(struct if_dwc_rk_softc *);
|
||||||
|
typedef void (*if_dwc_rk_phy_powerupfn_t)(struct if_dwc_rk_softc *);
|
||||||
|
|
||||||
|
struct if_dwc_rk_ops {
|
||||||
|
if_dwc_rk_set_delaysfn_t set_delays;
|
||||||
|
if_dwc_rk_set_speedfn_t set_speed;
|
||||||
|
if_dwc_rk_set_phy_modefn_t set_phy_mode;
|
||||||
|
if_dwc_rk_phy_powerupfn_t phy_powerup;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct if_dwc_rk_softc {
|
||||||
|
struct dwc_softc base;
|
||||||
|
uint32_t tx_delay;
|
||||||
|
uint32_t rx_delay;
|
||||||
|
bool integrated_phy;
|
||||||
|
bool clock_in;
|
||||||
|
phandle_t phy_node;
|
||||||
|
struct syscon *grf;
|
||||||
|
struct if_dwc_rk_ops *ops;
|
||||||
|
/* Common clocks */
|
||||||
|
clk_t mac_clk_rx;
|
||||||
|
clk_t mac_clk_tx;
|
||||||
|
clk_t aclk_mac;
|
||||||
|
clk_t pclk_mac;
|
||||||
|
clk_t clk_stmmaceth;
|
||||||
|
/* RMII clocks */
|
||||||
|
clk_t clk_mac_ref;
|
||||||
|
clk_t clk_mac_refout;
|
||||||
|
/* PHY clock */
|
||||||
|
clk_t clk_phy;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rk3328_set_delays(struct if_dwc_rk_softc *sc);
|
||||||
|
static int rk3328_set_speed(struct if_dwc_rk_softc *sc, int speed);
|
||||||
|
static void rk3328_set_phy_mode(struct if_dwc_rk_softc *sc);
|
||||||
|
static void rk3328_phy_powerup(struct if_dwc_rk_softc *sc);
|
||||||
|
|
||||||
|
static void rk3399_set_delays(struct if_dwc_rk_softc *sc);
|
||||||
|
static int rk3399_set_speed(struct if_dwc_rk_softc *sc, int speed);
|
||||||
|
|
||||||
|
static struct if_dwc_rk_ops rk3288_ops = {
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct if_dwc_rk_ops rk3328_ops = {
|
||||||
|
.set_delays = rk3328_set_delays,
|
||||||
|
.set_speed = rk3328_set_speed,
|
||||||
|
.set_phy_mode = rk3328_set_phy_mode,
|
||||||
|
.phy_powerup = rk3328_phy_powerup,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct if_dwc_rk_ops rk3399_ops = {
|
||||||
|
.set_delays = rk3399_set_delays,
|
||||||
|
.set_speed = rk3399_set_speed,
|
||||||
|
};
|
||||||
|
|
||||||
static struct ofw_compat_data compat_data[] = {
|
static struct ofw_compat_data compat_data[] = {
|
||||||
{"rockchip,rk3288-gmac", 1},
|
{"rockchip,rk3288-gmac", (uintptr_t)&rk3288_ops},
|
||||||
{"rockchip,rk3328-gmac", 1},
|
{"rockchip,rk3328-gmac", (uintptr_t)&rk3328_ops},
|
||||||
{"rockchip,rk3399-gmac", 1},
|
{"rockchip,rk3399-gmac", (uintptr_t)&rk3399_ops},
|
||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rk3328_set_delays(struct syscon *grf, phandle_t node)
|
rk3328_set_delays(struct if_dwc_rk_softc *sc)
|
||||||
{
|
{
|
||||||
|
uint32_t reg;
|
||||||
uint32_t tx, rx;
|
uint32_t tx, rx;
|
||||||
|
|
||||||
if (OF_getencprop(node, "tx_delay", &tx, sizeof(tx)) <= 0)
|
if (sc->base.phy_mode != PHY_MODE_RGMII)
|
||||||
tx = 0x30;
|
return;
|
||||||
if (OF_getencprop(node, "rx_delay", &rx, sizeof(rx)) <= 0)
|
|
||||||
rx = 0x10;
|
|
||||||
|
|
||||||
if (bootverbose)
|
reg = SYSCON_READ_4(sc->grf, RK3328_GRF_MAC_CON0);
|
||||||
printf("setting RK3328 RX/TX delays: %d/%d\n", rx, tx);
|
tx = ((reg >> MAC_CON0_GMAC2IO_TX_DL_CFG_SHIFT) & MAC_CON0_GMAC2IO_TX_DL_CFG_MASK);
|
||||||
tx = ((tx & RK3328_GRF_MAC_CON0_TX_MASK) <<
|
rx = ((reg >> MAC_CON0_GMAC2IO_RX_DL_CFG_SHIFT) & MAC_CON0_GMAC2IO_RX_DL_CFG_MASK);
|
||||||
RK3328_GRF_MAC_CON0_TX_SHIFT);
|
|
||||||
rx = ((rx & RK3328_GRF_MAC_CON0_TX_MASK) <<
|
|
||||||
RK3328_GRF_MAC_CON0_RX_SHIFT);
|
|
||||||
|
|
||||||
SYSCON_WRITE_4(grf, RK3328_GRF_MAC_CON0, tx | rx | 0xFFFF0000);
|
reg = SYSCON_READ_4(sc->grf, RK3328_GRF_MAC_CON1);
|
||||||
SYSCON_WRITE_4(grf, RK3328_GRF_MAC_CON1, RK3328_GRF_MAC_CON1_TX_ENA | RK3328_GRF_MAC_CON1_RX_ENA |
|
if (bootverbose) {
|
||||||
((RK3328_GRF_MAC_CON1_TX_ENA | RK3328_GRF_MAC_CON1_RX_ENA) << 16));
|
device_printf(sc->base.dev, "current delays settings: tx=%u(%s) rx=%u(%s)\n",
|
||||||
|
tx, ((reg & MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA) ? "enabled" : "disabled"),
|
||||||
|
rx, ((reg & MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA) ? "enabled" : "disabled"));
|
||||||
|
|
||||||
|
device_printf(sc->base.dev, "setting new RK3328 RX/TX delays: %d/%d\n",
|
||||||
|
sc->tx_delay, sc->rx_delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = (MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA | MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA) << 16;
|
||||||
|
reg |= (MAC_CON1_GMAC2IO_GMAC_TXCLK_DLY_ENA | MAC_CON1_GMAC2IO_GMAC_RXCLK_DLY_ENA);
|
||||||
|
SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON1, reg);
|
||||||
|
|
||||||
|
reg = 0xffff << 16;
|
||||||
|
reg |= ((sc->tx_delay & MAC_CON0_GMAC2IO_TX_DL_CFG_MASK) <<
|
||||||
|
MAC_CON0_GMAC2IO_TX_DL_CFG_SHIFT);
|
||||||
|
reg |= ((sc->rx_delay & MAC_CON0_GMAC2IO_TX_DL_CFG_MASK) <<
|
||||||
|
MAC_CON0_GMAC2IO_RX_DL_CFG_SHIFT);
|
||||||
|
SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON0, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RK3399_GRF_SOC_CON6 0xc218
|
static int
|
||||||
#define RK3399_GRF_SOC_CON6_TX_ENA (1 << 7)
|
rk3328_set_speed(struct if_dwc_rk_softc *sc, int speed)
|
||||||
#define RK3399_GRF_SOC_CON6_TX_MASK 0x7F
|
{
|
||||||
#define RK3399_GRF_SOC_CON6_TX_SHIFT 0
|
uint32_t reg;
|
||||||
#define RK3399_GRF_SOC_CON6_RX_MASK 0x7F
|
|
||||||
#define RK3399_GRF_SOC_CON6_RX_ENA (1 << 15)
|
switch (sc->base.phy_mode) {
|
||||||
#define RK3399_GRF_SOC_CON6_RX_SHIFT 8
|
case PHY_MODE_RGMII:
|
||||||
|
switch (speed) {
|
||||||
|
case IFM_1000_T:
|
||||||
|
case IFM_1000_SX:
|
||||||
|
reg = MAC_CON1_GMAC2IO_GMII_CLK_SEL_125;
|
||||||
|
break;
|
||||||
|
case IFM_100_TX:
|
||||||
|
reg = MAC_CON1_GMAC2IO_GMII_CLK_SEL_25;
|
||||||
|
break;
|
||||||
|
case IFM_10_T:
|
||||||
|
reg = MAC_CON1_GMAC2IO_GMII_CLK_SEL_2_5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
device_printf(sc->base.dev, "unsupported RGMII media %u\n", speed);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON1,
|
||||||
|
((MAC_CON1_GMAC2IO_GMII_CLK_SEL_MASK << 16) | reg));
|
||||||
|
break;
|
||||||
|
case PHY_MODE_RMII:
|
||||||
|
switch (speed) {
|
||||||
|
case IFM_100_TX:
|
||||||
|
reg = MAC_CON1_GMAC2IO_RMII_CLK_SEL_25 |
|
||||||
|
MAC_CON1_GMAC2IO_MAC_SPEED_100;
|
||||||
|
break;
|
||||||
|
case IFM_10_T:
|
||||||
|
reg = MAC_CON1_GMAC2IO_RMII_CLK_SEL_2_5 |
|
||||||
|
MAC_CON1_GMAC2IO_MAC_SPEED_10;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
device_printf(sc->base.dev, "unsupported RMII media %u\n", speed);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSCON_WRITE_4(sc->grf,
|
||||||
|
sc->integrated_phy ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1,
|
||||||
|
reg |
|
||||||
|
((MAC_CON1_GMAC2IO_RMII_CLK_SEL_MASK | MAC_CON1_GMAC2IO_MAC_SPEED_MASK) << 16));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rk3399_set_delays(struct syscon *grf, phandle_t node)
|
rk3328_set_phy_mode(struct if_dwc_rk_softc *sc)
|
||||||
{
|
{
|
||||||
uint32_t tx, rx;
|
|
||||||
|
|
||||||
if (OF_getencprop(node, "tx_delay", &tx, sizeof(tx)) <= 0)
|
switch (sc->base.phy_mode) {
|
||||||
tx = 0x30;
|
case PHY_MODE_RGMII:
|
||||||
if (OF_getencprop(node, "rx_delay", &rx, sizeof(rx)) <= 0)
|
SYSCON_WRITE_4(sc->grf, RK3328_GRF_MAC_CON1,
|
||||||
rx = 0x10;
|
((MAC_CON1_GMAC2IO_INTF_SEL_MASK | MAC_CON1_GMAC2IO_RMII_MODE_MASK) << 16) |
|
||||||
|
MAC_CON1_GMAC2IO_INTF_RGMII);
|
||||||
|
break;
|
||||||
|
case PHY_MODE_RMII:
|
||||||
|
SYSCON_WRITE_4(sc->grf, sc->integrated_phy ? RK3328_GRF_MAC_CON2 : RK3328_GRF_MAC_CON1,
|
||||||
|
((MAC_CON1_GMAC2IO_INTF_SEL_MASK | MAC_CON1_GMAC2IO_RMII_MODE_MASK) << 16) |
|
||||||
|
MAC_CON1_GMAC2IO_INTF_RMII | MAC_CON1_GMAC2IO_RMII_MODE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (bootverbose)
|
static void
|
||||||
printf("setting RK3399 RX/TX delays: %d/%d\n", rx, tx);
|
rk3328_phy_powerup(struct if_dwc_rk_softc *sc)
|
||||||
tx = ((tx & RK3399_GRF_SOC_CON6_TX_MASK) <<
|
{
|
||||||
RK3399_GRF_SOC_CON6_TX_SHIFT) | RK3399_GRF_SOC_CON6_TX_ENA;
|
SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON1,
|
||||||
rx = ((rx & RK3399_GRF_SOC_CON6_TX_MASK) <<
|
(MACPHY_CON1_RMII_MODE_MASK << 16) |
|
||||||
RK3399_GRF_SOC_CON6_RX_SHIFT) | RK3399_GRF_SOC_CON6_RX_ENA;
|
MACPHY_CON1_RMII_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
SYSCON_WRITE_4(grf, RK3399_GRF_SOC_CON6, tx | rx | 0xFFFF0000);
|
static void
|
||||||
|
rk3399_set_delays(struct if_dwc_rk_softc *sc)
|
||||||
|
{
|
||||||
|
uint32_t reg, tx, rx;
|
||||||
|
|
||||||
|
if (sc->base.phy_mode != PHY_MODE_RGMII)
|
||||||
|
return;
|
||||||
|
|
||||||
|
reg = SYSCON_READ_4(sc->grf, RK3399_GRF_SOC_CON6);
|
||||||
|
tx = ((reg >> SOC_CON6_TX_DL_CFG_SHIFT) & SOC_CON6_TX_DL_CFG_MASK);
|
||||||
|
rx = ((reg >> SOC_CON6_RX_DL_CFG_SHIFT) & SOC_CON6_RX_DL_CFG_MASK);
|
||||||
|
|
||||||
|
if (bootverbose) {
|
||||||
|
device_printf(sc->base.dev, "current delays settings: tx=%u(%s) rx=%u(%s)\n",
|
||||||
|
tx, ((reg & SOC_CON6_GMAC_TXCLK_DLY_ENA) ? "enabled" : "disabled"),
|
||||||
|
rx, ((reg & SOC_CON6_GMAC_RXCLK_DLY_ENA) ? "enabled" : "disabled"));
|
||||||
|
|
||||||
|
device_printf(sc->base.dev, "setting new RK3399 RX/TX delays: %d/%d\n",
|
||||||
|
sc->rx_delay, sc->tx_delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = 0xFFFF << 16;
|
||||||
|
reg |= ((sc->tx_delay & SOC_CON6_TX_DL_CFG_MASK) <<
|
||||||
|
SOC_CON6_TX_DL_CFG_SHIFT);
|
||||||
|
reg |= ((sc->rx_delay & SOC_CON6_RX_DL_CFG_MASK) <<
|
||||||
|
SOC_CON6_RX_DL_CFG_SHIFT);
|
||||||
|
reg |= SOC_CON6_GMAC_TXCLK_DLY_ENA | SOC_CON6_GMAC_RXCLK_DLY_ENA;
|
||||||
|
|
||||||
|
SYSCON_WRITE_4(sc->grf, RK3399_GRF_SOC_CON6, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rk3399_set_speed(struct if_dwc_rk_softc *sc, int speed)
|
||||||
|
{
|
||||||
|
uint32_t reg;
|
||||||
|
|
||||||
|
switch (speed) {
|
||||||
|
case IFM_1000_T:
|
||||||
|
case IFM_1000_SX:
|
||||||
|
reg = SOC_CON5_GMAC_CLK_SEL_125;
|
||||||
|
break;
|
||||||
|
case IFM_100_TX:
|
||||||
|
reg = SOC_CON5_GMAC_CLK_SEL_25;
|
||||||
|
break;
|
||||||
|
case IFM_10_T:
|
||||||
|
reg = SOC_CON5_GMAC_CLK_SEL_2_5;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
device_printf(sc->base.dev, "unsupported media %u\n", speed);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSCON_WRITE_4(sc->grf, RK3399_GRF_SOC_CON5,
|
||||||
|
((SOC_CON5_GMAC_CLK_SEL_MASK << 16) | reg));
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
if_dwc_rk_sysctl_delays(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
struct if_dwc_rk_softc *sc;
|
||||||
|
int rv;
|
||||||
|
uint32_t rxtx;
|
||||||
|
|
||||||
|
sc = arg1;
|
||||||
|
rxtx = ((sc->rx_delay << 8) | sc->tx_delay);
|
||||||
|
|
||||||
|
rv = sysctl_handle_int(oidp, &rxtx, 0, req);
|
||||||
|
if (rv != 0 || req->newptr == NULL)
|
||||||
|
return (rv);
|
||||||
|
sc->tx_delay = rxtx & 0xff;
|
||||||
|
sc->rx_delay = (rxtx >> 8) & 0xff;
|
||||||
|
|
||||||
|
if (sc->ops->set_delays)
|
||||||
|
sc->ops->set_delays(sc);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
if_dwc_rk_init_sysctl(struct if_dwc_rk_softc *sc)
|
||||||
|
{
|
||||||
|
struct sysctl_oid *child;
|
||||||
|
struct sysctl_ctx_list *ctx_list;
|
||||||
|
|
||||||
|
ctx_list = device_get_sysctl_ctx(sc->base.dev);
|
||||||
|
child = device_get_sysctl_tree(sc->base.dev);
|
||||||
|
SYSCTL_ADD_PROC(ctx_list,
|
||||||
|
SYSCTL_CHILDREN(child), OID_AUTO, "delays",
|
||||||
|
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, sc, 0,
|
||||||
|
if_dwc_rk_sysctl_delays, "", "RGMII RX/TX delays: ((rx << 8) | tx)");
|
||||||
|
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -136,26 +389,189 @@ if_dwc_rk_probe(device_t dev)
|
|||||||
return (BUS_PROBE_DEFAULT);
|
return (BUS_PROBE_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
if_dwc_rk_init_clocks(device_t dev)
|
||||||
|
{
|
||||||
|
struct if_dwc_rk_softc *sc;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
error = clk_set_assigned(dev, ofw_bus_get_node(dev));
|
||||||
|
if (error != 0) {
|
||||||
|
device_printf(dev, "clk_set_assigned failed\n");
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable clocks */
|
||||||
|
error = clk_get_by_ofw_name(dev, 0, "stmmaceth", &sc->clk_stmmaceth);
|
||||||
|
if (error != 0) {
|
||||||
|
device_printf(dev, "could not find clock stmmaceth\n");
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clk_get_by_ofw_name(dev, 0, "mac_clk_rx", &sc->mac_clk_rx) != 0) {
|
||||||
|
device_printf(sc->base.dev, "could not get mac_clk_rx clock\n");
|
||||||
|
sc->mac_clk_rx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clk_get_by_ofw_name(dev, 0, "mac_clk_tx", &sc->mac_clk_tx) != 0) {
|
||||||
|
device_printf(sc->base.dev, "could not get mac_clk_tx clock\n");
|
||||||
|
sc->mac_clk_tx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clk_get_by_ofw_name(dev, 0, "aclk_mac", &sc->aclk_mac) != 0) {
|
||||||
|
device_printf(sc->base.dev, "could not get aclk_mac clock\n");
|
||||||
|
sc->aclk_mac = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clk_get_by_ofw_name(dev, 0, "pclk_mac", &sc->pclk_mac) != 0) {
|
||||||
|
device_printf(sc->base.dev, "could not get pclk_mac clock\n");
|
||||||
|
sc->pclk_mac = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->base.phy_mode == PHY_MODE_RGMII) {
|
||||||
|
if (clk_get_by_ofw_name(dev, 0, "clk_mac_ref", &sc->clk_mac_ref) != 0) {
|
||||||
|
device_printf(sc->base.dev, "could not get clk_mac_ref clock\n");
|
||||||
|
sc->clk_mac_ref = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sc->clock_in) {
|
||||||
|
if (clk_get_by_ofw_name(dev, 0, "clk_mac_refout", &sc->clk_mac_refout) != 0) {
|
||||||
|
device_printf(sc->base.dev, "could not get clk_mac_refout clock\n");
|
||||||
|
sc->clk_mac_refout = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
clk_set_freq(sc->clk_stmmaceth, 50000000, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sc->phy_node != 0) && sc->integrated_phy) {
|
||||||
|
if (clk_get_by_ofw_index(dev, sc->phy_node, 0, &sc->clk_phy) != 0) {
|
||||||
|
device_printf(sc->base.dev, "could not get PHY clock\n");
|
||||||
|
sc->clk_phy = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->clk_phy) {
|
||||||
|
clk_set_freq(sc->clk_phy, 50000000, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->base.phy_mode == PHY_MODE_RMII) {
|
||||||
|
if (sc->mac_clk_rx)
|
||||||
|
clk_enable(sc->mac_clk_rx);
|
||||||
|
if (sc->clk_mac_ref)
|
||||||
|
clk_enable(sc->clk_mac_ref);
|
||||||
|
if (sc->clk_mac_refout)
|
||||||
|
clk_enable(sc->clk_mac_refout);
|
||||||
|
}
|
||||||
|
if (sc->clk_phy)
|
||||||
|
clk_enable(sc->clk_phy);
|
||||||
|
if (sc->aclk_mac)
|
||||||
|
clk_enable(sc->aclk_mac);
|
||||||
|
if (sc->pclk_mac)
|
||||||
|
clk_enable(sc->pclk_mac);
|
||||||
|
if (sc->mac_clk_tx)
|
||||||
|
clk_enable(sc->mac_clk_tx);
|
||||||
|
|
||||||
|
DELAY(50);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
if_dwc_rk_init(device_t dev)
|
if_dwc_rk_init(device_t dev)
|
||||||
{
|
{
|
||||||
|
struct if_dwc_rk_softc *sc;
|
||||||
phandle_t node;
|
phandle_t node;
|
||||||
struct syscon *grf = NULL;
|
uint32_t rx, tx;
|
||||||
|
int err;
|
||||||
|
pcell_t phy_handle;
|
||||||
|
char *clock_in_out;
|
||||||
|
hwreset_t phy_reset;
|
||||||
|
regulator_t phy_supply;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
node = ofw_bus_get_node(dev);
|
node = ofw_bus_get_node(dev);
|
||||||
|
sc->ops = (struct if_dwc_rk_ops *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
|
||||||
if (OF_hasprop(node, "rockchip,grf") &&
|
if (OF_hasprop(node, "rockchip,grf") &&
|
||||||
syscon_get_by_ofw_property(dev, node,
|
syscon_get_by_ofw_property(dev, node,
|
||||||
"rockchip,grf", &grf) != 0) {
|
"rockchip,grf", &sc->grf) != 0) {
|
||||||
device_printf(dev, "cannot get grf driver handle\n");
|
device_printf(dev, "cannot get grf driver handle\n");
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ofw_bus_is_compatible(dev, "rockchip,rk3399-gmac"))
|
if (OF_getencprop(node, "tx_delay", &tx, sizeof(tx)) <= 0)
|
||||||
rk3399_set_delays(grf, node);
|
tx = 0x30;
|
||||||
else if (ofw_bus_is_compatible(dev, "rockchip,rk3328-gmac"))
|
if (OF_getencprop(node, "rx_delay", &rx, sizeof(rx)) <= 0)
|
||||||
rk3328_set_delays(grf, node);
|
rx = 0x10;
|
||||||
|
sc->tx_delay = tx;
|
||||||
|
sc->rx_delay = rx;
|
||||||
|
|
||||||
/* Mode should be set according to dtb property */
|
sc->clock_in = true;
|
||||||
|
if (OF_getprop_alloc(node, "clock_in_out", (void **)&clock_in_out)) {
|
||||||
|
if (strcmp(clock_in_out, "input") == 0)
|
||||||
|
sc->clock_in = true;
|
||||||
|
else
|
||||||
|
sc->clock_in = false;
|
||||||
|
OF_prop_free(clock_in_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OF_getencprop(node, "phy-handle", (void *)&phy_handle,
|
||||||
|
sizeof(phy_handle)) > 0)
|
||||||
|
sc->phy_node = OF_node_from_xref(phy_handle);
|
||||||
|
|
||||||
|
if (sc->phy_node)
|
||||||
|
sc->integrated_phy = OF_hasprop(sc->phy_node, "phy-is-integrated");
|
||||||
|
|
||||||
|
if (sc->integrated_phy)
|
||||||
|
device_printf(sc->base.dev, "PHY is integrated\n");
|
||||||
|
|
||||||
|
if_dwc_rk_init_clocks(dev);
|
||||||
|
|
||||||
|
if (sc->ops->set_phy_mode)
|
||||||
|
sc->ops->set_phy_mode(sc);
|
||||||
|
|
||||||
|
if (sc->ops->set_delays)
|
||||||
|
sc->ops->set_delays(sc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this also sets delays if tunable is defined
|
||||||
|
*/
|
||||||
|
err = if_dwc_rk_init_sysctl(sc);
|
||||||
|
if (err != 0)
|
||||||
|
return (err);
|
||||||
|
|
||||||
|
if (regulator_get_by_ofw_property(sc->base.dev, 0,
|
||||||
|
"phy-supply", &phy_supply) == 0) {
|
||||||
|
if (regulator_enable(phy_supply)) {
|
||||||
|
device_printf(sc->base.dev,
|
||||||
|
"cannot enable 'phy' regulator\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
device_printf(sc->base.dev, "no phy-supply property\n");
|
||||||
|
|
||||||
|
/* Power up */
|
||||||
|
if (sc->integrated_phy) {
|
||||||
|
if (sc->ops->phy_powerup)
|
||||||
|
sc->ops->phy_powerup(sc);
|
||||||
|
|
||||||
|
SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON0,
|
||||||
|
(MACPHY_CON0_CLK_50M_MASK << 16) |
|
||||||
|
MACPHY_CON0_CLK_50M);
|
||||||
|
SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON0,
|
||||||
|
(MACPHY_CON0_RMII_MODE_MASK << 16) |
|
||||||
|
MACPHY_CON0_RMII_MODE);
|
||||||
|
SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON2, 0xffff1234);
|
||||||
|
SYSCON_WRITE_4(sc->grf, RK3328_GRF_MACPHY_CON3, 0x003f0035);
|
||||||
|
|
||||||
|
if (hwreset_get_by_ofw_idx(dev, sc->phy_node, 0, &phy_reset) == 0) {
|
||||||
|
hwreset_assert(phy_reset);
|
||||||
|
DELAY(20);
|
||||||
|
hwreset_deassert(phy_reset);
|
||||||
|
DELAY(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -175,12 +591,26 @@ if_dwc_rk_mii_clk(device_t dev)
|
|||||||
return (GMAC_MII_CLK_150_250M_DIV102);
|
return (GMAC_MII_CLK_150_250M_DIV102);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
if_dwc_rk_set_speed(device_t dev, int speed)
|
||||||
|
{
|
||||||
|
struct if_dwc_rk_softc *sc;
|
||||||
|
|
||||||
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
|
if (sc->ops->set_speed)
|
||||||
|
return sc->ops->set_speed(sc, speed);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static device_method_t if_dwc_rk_methods[] = {
|
static device_method_t if_dwc_rk_methods[] = {
|
||||||
DEVMETHOD(device_probe, if_dwc_rk_probe),
|
DEVMETHOD(device_probe, if_dwc_rk_probe),
|
||||||
|
|
||||||
DEVMETHOD(if_dwc_init, if_dwc_rk_init),
|
DEVMETHOD(if_dwc_init, if_dwc_rk_init),
|
||||||
DEVMETHOD(if_dwc_mac_type, if_dwc_rk_mac_type),
|
DEVMETHOD(if_dwc_mac_type, if_dwc_rk_mac_type),
|
||||||
DEVMETHOD(if_dwc_mii_clk, if_dwc_rk_mii_clk),
|
DEVMETHOD(if_dwc_mii_clk, if_dwc_rk_mii_clk),
|
||||||
|
DEVMETHOD(if_dwc_set_speed, if_dwc_rk_set_speed),
|
||||||
|
|
||||||
DEVMETHOD_END
|
DEVMETHOD_END
|
||||||
};
|
};
|
||||||
@ -190,6 +620,6 @@ static devclass_t dwc_rk_devclass;
|
|||||||
extern driver_t dwc_driver;
|
extern driver_t dwc_driver;
|
||||||
|
|
||||||
DEFINE_CLASS_1(dwc, dwc_rk_driver, if_dwc_rk_methods,
|
DEFINE_CLASS_1(dwc, dwc_rk_driver, if_dwc_rk_methods,
|
||||||
sizeof(struct dwc_softc), dwc_driver);
|
sizeof(struct if_dwc_rk_softc), dwc_driver);
|
||||||
DRIVER_MODULE(dwc_rk, simplebus, dwc_rk_driver, dwc_rk_devclass, 0, 0);
|
DRIVER_MODULE(dwc_rk, simplebus, dwc_rk_driver, dwc_rk_devclass, 0, 0);
|
||||||
MODULE_DEPEND(dwc_rk, dwc, 1, 1, 1);
|
MODULE_DEPEND(dwc_rk, dwc, 1, 1, 1);
|
||||||
|
@ -1209,14 +1209,22 @@ dwc_clock_init(device_t dev)
|
|||||||
hwreset_t rst;
|
hwreset_t rst;
|
||||||
clk_t clk;
|
clk_t clk;
|
||||||
int error;
|
int error;
|
||||||
|
int64_t freq;
|
||||||
|
|
||||||
/* Enable clock */
|
/* Enable clocks */
|
||||||
if (clk_get_by_ofw_name(dev, 0, "stmmaceth", &clk) == 0) {
|
if (clk_get_by_ofw_name(dev, 0, "stmmaceth", &clk) == 0) {
|
||||||
error = clk_enable(clk);
|
error = clk_enable(clk);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
device_printf(dev, "could not enable main clock\n");
|
device_printf(dev, "could not enable main clock\n");
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
if (bootverbose) {
|
||||||
|
clk_get_freq(clk, &freq);
|
||||||
|
device_printf(dev, "MAC clock(%s) freq: %ld\n", clk_get_name(clk), freq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
device_printf(dev, "could not find clock stmmaceth\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* De-assert reset */
|
/* De-assert reset */
|
||||||
@ -1254,6 +1262,8 @@ dwc_attach(device_t dev)
|
|||||||
struct ifnet *ifp;
|
struct ifnet *ifp;
|
||||||
int error, i;
|
int error, i;
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
|
char *phy_mode;
|
||||||
|
phandle_t node;
|
||||||
|
|
||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
sc->dev = dev;
|
sc->dev = dev;
|
||||||
@ -1262,6 +1272,15 @@ dwc_attach(device_t dev)
|
|||||||
sc->mii_clk = IF_DWC_MII_CLK(dev);
|
sc->mii_clk = IF_DWC_MII_CLK(dev);
|
||||||
sc->mactype = IF_DWC_MAC_TYPE(dev);
|
sc->mactype = IF_DWC_MAC_TYPE(dev);
|
||||||
|
|
||||||
|
node = ofw_bus_get_node(dev);
|
||||||
|
if (OF_getprop_alloc(node, "phy-mode", (void **)&phy_mode)) {
|
||||||
|
if (strcmp(phy_mode, "rgmii") == 0)
|
||||||
|
sc->phy_mode = PHY_MODE_RGMII;
|
||||||
|
if (strcmp(phy_mode, "rmii") == 0)
|
||||||
|
sc->phy_mode = PHY_MODE_RMII;
|
||||||
|
OF_prop_free(phy_mode);
|
||||||
|
}
|
||||||
|
|
||||||
if (IF_DWC_INIT(dev) != 0)
|
if (IF_DWC_INIT(dev) != 0)
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
|
|
||||||
@ -1475,6 +1494,9 @@ dwc_miibus_statchg(device_t dev)
|
|||||||
else
|
else
|
||||||
reg &= ~(CONF_DM);
|
reg &= ~(CONF_DM);
|
||||||
WRITE4(sc, MAC_CONFIGURATION, reg);
|
WRITE4(sc, MAC_CONFIGURATION, reg);
|
||||||
|
|
||||||
|
IF_DWC_SET_SPEED(dev, IFM_SUBTYPE(mii->mii_media_active));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static device_method_t dwc_methods[] = {
|
static device_method_t dwc_methods[] = {
|
||||||
|
@ -37,6 +37,10 @@
|
|||||||
#ifndef __IF_DWC_H__
|
#ifndef __IF_DWC_H__
|
||||||
#define __IF_DWC_H__
|
#define __IF_DWC_H__
|
||||||
|
|
||||||
|
#define PHY_MODE_UNKNOWN 0x0
|
||||||
|
#define PHY_MODE_RMII 0x1
|
||||||
|
#define PHY_MODE_RGMII 0x2
|
||||||
|
|
||||||
#define MAC_CONFIGURATION 0x0
|
#define MAC_CONFIGURATION 0x0
|
||||||
#define CONF_JD (1 << 22) /* jabber timer disable */
|
#define CONF_JD (1 << 22) /* jabber timer disable */
|
||||||
#define CONF_BE (1 << 21) /* Frame Burst Enable */
|
#define CONF_BE (1 << 21) /* Frame Burst Enable */
|
||||||
|
@ -49,6 +49,12 @@ CODE {
|
|||||||
{
|
{
|
||||||
return (GMAC_MII_CLK_25_35M_DIV16);
|
return (GMAC_MII_CLK_25_35M_DIV16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
if_dwc_default_set_speed(device_t dev, int speed)
|
||||||
|
{
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
HEADER {
|
HEADER {
|
||||||
@ -74,3 +80,11 @@ METHOD int mac_type {
|
|||||||
METHOD int mii_clk {
|
METHOD int mii_clk {
|
||||||
device_t dev;
|
device_t dev;
|
||||||
} DEFAULT if_dwc_default_mii_clk;
|
} DEFAULT if_dwc_default_mii_clk;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Signal media change to a specific hardware
|
||||||
|
#
|
||||||
|
METHOD int set_speed {
|
||||||
|
device_t dev;
|
||||||
|
int speed;
|
||||||
|
} DEFAULT if_dwc_default_set_speed;
|
||||||
|
@ -71,6 +71,7 @@ struct dwc_softc {
|
|||||||
boolean_t is_detaching;
|
boolean_t is_detaching;
|
||||||
int tx_watchdog_count;
|
int tx_watchdog_count;
|
||||||
int stats_harvest_count;
|
int stats_harvest_count;
|
||||||
|
int phy_mode;
|
||||||
|
|
||||||
/* RX */
|
/* RX */
|
||||||
bus_dma_tag_t rxdesc_tag;
|
bus_dma_tag_t rxdesc_tag;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user