version 1.3, 2018/06/19 23:43:11 |
version 1.3.4.1, 2019/06/10 22:05:55 |
Line 47 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 47 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <dev/ic/dwc_gmac_reg.h> |
#include <dev/ic/dwc_gmac_reg.h> |
|
|
#include <dev/fdt/fdtvar.h> |
#include <dev/fdt/fdtvar.h> |
|
#include <dev/fdt/syscon.h> |
|
|
|
#define RK_GMAC_TXDLY_DEFAULT 0x30 |
|
#define RK_GMAC_RXDLY_DEFAULT 0x10 |
|
|
|
enum rk_gmac_type { |
|
GMAC_RK3328 = 1, |
|
GMAC_RK3399 |
|
}; |
|
|
|
static const struct of_compat_data compat_data[] = { |
|
{ "rockchip,rk3328-gmac", GMAC_RK3328 }, |
|
{ "rockchip,rk3399-gmac", GMAC_RK3399 }, |
|
{ NULL } |
|
}; |
|
|
|
struct rk_gmac_softc { |
|
struct dwc_gmac_softc sc_base; |
|
struct syscon *sc_syscon; |
|
enum rk_gmac_type sc_type; |
|
}; |
|
|
|
/* |
|
* RK3328 specific |
|
*/ |
|
|
#define RK3328_GRF_MAC_CON0 0x0900 |
#define RK3328_GRF_MAC_CON0 0x0900 |
#define RK3328_GRF_MAC_CON0_RXDLY __BITS(13,7) |
#define RK3328_GRF_MAC_CON0_RXDLY __BITS(13,7) |
Line 63 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 88 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#define RK3328_GRF_MAC_CON1_RXDLY_EN __BIT(1) |
#define RK3328_GRF_MAC_CON1_RXDLY_EN __BIT(1) |
#define RK3328_GRF_MAC_CON1_TXDLY_EN __BIT(0) |
#define RK3328_GRF_MAC_CON1_TXDLY_EN __BIT(0) |
|
|
#define RK_GMAC_TXDLY_DEFAULT 0x30 |
|
#define RK_GMAC_RXDLY_DEFAULT 0x10 |
|
|
|
static const char * compatible[] = { |
|
"rockchip,rk3328-gmac", |
|
NULL |
|
}; |
|
|
|
struct rk_gmac_softc { |
|
struct dwc_gmac_softc sc_base; |
|
bus_space_handle_t sc_grf_bsh; |
|
}; |
|
|
|
static int |
|
rk_gmac_reset(const int phandle) |
|
{ |
|
struct fdtbus_gpio_pin *pin_reset; |
|
const u_int *reset_delay_us; |
|
bool reset_active_low; |
|
int len; |
|
|
|
if (!of_hasprop(phandle, "snps,reset-gpio")) |
|
return 0; |
|
|
|
pin_reset = fdtbus_gpio_acquire(phandle, "snps,reset-gpio", GPIO_PIN_OUTPUT); |
|
if (pin_reset == NULL) |
|
return ENOENT; |
|
|
|
reset_delay_us = fdtbus_get_prop(phandle, "snps,reset-delays-us", &len); |
|
if (reset_delay_us == NULL || len != 12) |
|
return ENXIO; |
|
|
|
reset_active_low = of_hasprop(phandle, "snps,reset-active-low"); |
|
|
|
fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0); |
|
delay(be32toh(reset_delay_us[0])); |
|
fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 0 : 1); |
|
delay(be32toh(reset_delay_us[1])); |
|
fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0); |
|
delay(be32toh(reset_delay_us[2])); |
|
|
|
return 0; |
|
} |
|
|
|
static int |
|
rk_gmac_intr(void *arg) |
|
{ |
|
return dwc_gmac_intr(arg); |
|
} |
|
|
|
static void |
static void |
rk3328_gmac_set_mode_rgmii(struct dwc_gmac_softc *sc, u_int tx_delay, u_int rx_delay) |
rk3328_gmac_set_mode_rgmii(struct dwc_gmac_softc *sc, u_int tx_delay, u_int rx_delay) |
{ |
{ |
struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc; |
struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc; |
uint32_t write_mask, write_val; |
uint32_t write_mask, write_val; |
|
|
|
syscon_lock(rk_sc->sc_syscon); |
|
|
write_mask = (RK3328_GRF_MAC_CON1_MODE | RK3328_GRF_MAC_CON1_SEL) << 16; |
write_mask = (RK3328_GRF_MAC_CON1_MODE | RK3328_GRF_MAC_CON1_SEL) << 16; |
write_val = __SHIFTIN(RK3328_GRF_MAC_CON1_SEL_RGMII, RK3328_GRF_MAC_CON1_SEL); |
write_val = __SHIFTIN(RK3328_GRF_MAC_CON1_SEL_RGMII, RK3328_GRF_MAC_CON1_SEL); |
bus_space_write_4(sc->sc_bst, rk_sc->sc_grf_bsh, RK3328_GRF_MAC_CON1, |
syscon_write_4(rk_sc->sc_syscon, RK3328_GRF_MAC_CON1, write_mask | write_val); |
write_mask | write_val); |
|
|
|
#if notyet |
#if notyet |
write_mask = (RK3328_GRF_MAC_CON0_TXDLY | RK3328_GRF_MAC_CON0_RXDLY) << 16; |
write_mask = (RK3328_GRF_MAC_CON0_TXDLY | RK3328_GRF_MAC_CON0_RXDLY) << 16; |
write_val = __SHIFTIN(tx_delay, RK3328_GRF_MAC_CON0_TXDLY) | |
write_val = __SHIFTIN(tx_delay, RK3328_GRF_MAC_CON0_TXDLY) | |
__SHIFTIN(rx_delay, RK3328_GRF_MAC_CON0_RXDLY); |
__SHIFTIN(rx_delay, RK3328_GRF_MAC_CON0_RXDLY); |
bus_space_write_4(sc->sc_bst, rk_sc->sc_grf_bsh, RK3328_GRF_MAC_CON0, |
syscon_write_4(rk_sc->sc_syscon, RK3328_GRF_MAC_CON0, write_mask | write_val); |
write_mask | write_val); |
|
|
|
write_mask = (RK3328_GRF_MAC_CON1_RXDLY_EN | RK3328_GRF_MAC_CON1_TXDLY_EN) << 16; |
write_mask = (RK3328_GRF_MAC_CON1_RXDLY_EN | RK3328_GRF_MAC_CON1_TXDLY_EN) << 16; |
write_val = RK3328_GRF_MAC_CON1_RXDLY_EN | RK3328_GRF_MAC_CON1_TXDLY_EN; |
write_val = RK3328_GRF_MAC_CON1_RXDLY_EN | RK3328_GRF_MAC_CON1_TXDLY_EN; |
bus_space_write_4(sc->sc_bst, rk_sc->sc_grf_bsh, RK3328_GRF_MAC_CON1, |
syscon_write_4(rk_sc->sc_syscon, RK3328_GRF_MAC_CON1, write_mask | write_val); |
write_mask | write_val); |
|
#endif |
#endif |
|
|
|
syscon_unlock(rk_sc->sc_syscon); |
} |
} |
|
|
static void |
static void |
rk3328_gmac_set_speed_rgmii(struct dwc_gmac_softc *sc, int speed) |
rk3328_gmac_set_speed_rgmii(struct dwc_gmac_softc *sc, int speed) |
{ |
{ |
struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc; |
struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc; |
|
#if 0 |
u_int clksel; |
u_int clksel; |
|
|
switch (speed) { |
switch (speed) { |
Line 155 rk3328_gmac_set_speed_rgmii(struct dwc_g |
|
Line 132 rk3328_gmac_set_speed_rgmii(struct dwc_g |
|
clksel = RK3328_GRF_MAC_CON1_CLKSEL_125M; |
clksel = RK3328_GRF_MAC_CON1_CLKSEL_125M; |
break; |
break; |
} |
} |
|
#endif |
|
|
bus_space_write_4(sc->sc_bst, rk_sc->sc_grf_bsh, RK3328_GRF_MAC_CON1, |
syscon_lock(rk_sc->sc_syscon); |
|
syscon_write_4(rk_sc->sc_syscon, RK3328_GRF_MAC_CON1, |
(RK3328_GRF_MAC_CON1_CLKSEL << 16) | |
(RK3328_GRF_MAC_CON1_CLKSEL << 16) | |
__SHIFTIN(RK3328_GRF_MAC_CON1_CLKSEL_125M, RK3328_GRF_MAC_CON1_CLKSEL)); |
__SHIFTIN(RK3328_GRF_MAC_CON1_CLKSEL_125M, RK3328_GRF_MAC_CON1_CLKSEL)); |
|
syscon_unlock(rk_sc->sc_syscon); |
|
} |
|
|
|
/* |
|
* RK3399 specific |
|
*/ |
|
|
|
#define RK3399_GRF_SOC_CON5 0x0c214 |
|
#define RK3399_GRF_SOC_CON5_GMAC_PHY_INTF_SEL __BITS(11,9) |
|
#define RK3399_GRF_SOC_CON5_GMAC_FLOWCTRL __BIT(8) |
|
#define RK3399_GRF_SOC_CON5_GMAC_SPEED __BIT(7) |
|
#define RK3399_GRF_SOC_CON5_RMII_MODE __BIT(6) |
|
#define RK3399_GRF_SOC_CON5_GMAC_CLK_SEL __BITS(5,4) |
|
#define RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_125M 0 |
|
#define RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_25M 3 |
|
#define RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_2_5M 2 |
|
#define RK3399_GRF_SOC_CON5_RMII_CLK_SEL __BIT(3) |
|
#define RK3399_GRF_SOC_CON6 0x0c218 |
|
#define RK3399_GRF_SOC_CON6_GMAC_RXCLK_DLY_ENA __BIT(15) |
|
#define RK3399_GRF_SOC_CON6_GMAC_CLK_RX_DL_CFG __BITS(14,8) |
|
#define RK3399_GRF_SOC_CON6_GMAC_TXCLK_DLY_ENA __BIT(7) |
|
#define RK3399_GRF_SOC_CON6_GMAC_CLK_TX_DL_CFG __BITS(6,0) |
|
|
|
static void |
|
rk3399_gmac_set_mode_rgmii(struct dwc_gmac_softc *sc, u_int tx_delay, u_int rx_delay) |
|
{ |
|
struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc; |
|
|
|
const uint32_t con5_mask = |
|
(RK3399_GRF_SOC_CON5_RMII_MODE | RK3399_GRF_SOC_CON5_GMAC_PHY_INTF_SEL) << 16; |
|
const uint32_t con5 = __SHIFTIN(1, RK3399_GRF_SOC_CON5_GMAC_PHY_INTF_SEL); |
|
|
|
#if notyet |
|
const uint32_t con6_mask = |
|
(RK3399_GRF_SOC_CON6_GMAC_RXCLK_DLY_ENA | |
|
RK3399_GRF_SOC_CON6_GMAC_TXCLK_DLY_ENA | |
|
RK3399_GRF_SOC_CON6_GMAC_CLK_RX_DL_CFG | |
|
RK3399_GRF_SOC_CON6_GMAC_CLK_TX_DL_CFG) << 16; |
|
const uint32_t con6 = |
|
(tx_delay ? RK3399_GRF_SOC_CON6_GMAC_TXCLK_DLY_ENA : 0) | |
|
(rx_delay ? RK3399_GRF_SOC_CON6_GMAC_RXCLK_DLY_ENA : 0) | |
|
__SHIFTIN(rx_delay, RK3399_GRF_SOC_CON6_GMAC_CLK_RX_DL_CFG) | |
|
__SHIFTIN(tx_delay, RK3399_GRF_SOC_CON6_GMAC_CLK_TX_DL_CFG); |
|
#endif |
|
|
|
syscon_lock(rk_sc->sc_syscon); |
|
syscon_write_4(rk_sc->sc_syscon, RK3399_GRF_SOC_CON5, con5 | con5_mask); |
|
#if notyet |
|
syscon_write_4(rk_sc->sc_syscon, RK3399_GRF_SOC_CON6, con6 | con6_mask); |
|
#endif |
|
syscon_unlock(rk_sc->sc_syscon); |
|
} |
|
|
|
static void |
|
rk3399_gmac_set_speed_rgmii(struct dwc_gmac_softc *sc, int speed) |
|
{ |
|
struct rk_gmac_softc * const rk_sc = (struct rk_gmac_softc *)sc; |
|
u_int clksel; |
|
|
|
switch (speed) { |
|
case IFM_10_T: |
|
clksel = RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_2_5M; |
|
break; |
|
case IFM_100_TX: |
|
clksel = RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_25M; |
|
break; |
|
default: |
|
clksel = RK3399_GRF_SOC_CON5_GMAC_CLK_SEL_125M; |
|
break; |
|
} |
|
|
|
const uint32_t con5_mask = |
|
RK3399_GRF_SOC_CON5_GMAC_CLK_SEL << 16; |
|
const uint32_t con5 = |
|
__SHIFTIN(clksel, RK3399_GRF_SOC_CON5_GMAC_CLK_SEL); |
|
|
|
syscon_lock(rk_sc->sc_syscon); |
|
syscon_write_4(rk_sc->sc_syscon, RK3399_GRF_SOC_CON5, con5 | con5_mask); |
|
syscon_unlock(rk_sc->sc_syscon); |
|
} |
|
|
|
static int |
|
rk_gmac_reset(const int phandle) |
|
{ |
|
struct fdtbus_gpio_pin *pin_reset; |
|
const u_int *reset_delay_us; |
|
bool reset_active_low; |
|
int len; |
|
|
|
if (!of_hasprop(phandle, "snps,reset-gpio")) |
|
return 0; |
|
|
|
pin_reset = fdtbus_gpio_acquire(phandle, "snps,reset-gpio", GPIO_PIN_OUTPUT); |
|
if (pin_reset == NULL) |
|
return ENOENT; |
|
|
|
reset_delay_us = fdtbus_get_prop(phandle, "snps,reset-delays-us", &len); |
|
if (reset_delay_us == NULL || len != 12) |
|
return ENXIO; |
|
|
|
reset_active_low = of_hasprop(phandle, "snps,reset-active-low"); |
|
|
|
fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0); |
|
delay(be32toh(reset_delay_us[0])); |
|
fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 0 : 1); |
|
delay(be32toh(reset_delay_us[1])); |
|
fdtbus_gpio_write_raw(pin_reset, reset_active_low ? 1 : 0); |
|
delay(be32toh(reset_delay_us[2])); |
|
|
|
return 0; |
|
} |
|
|
|
static int |
|
rk_gmac_intr(void *arg) |
|
{ |
|
return dwc_gmac_intr(arg); |
} |
} |
|
|
static int |
static int |
Line 228 rk_gmac_match(device_t parent, cfdata_t |
|
Line 323 rk_gmac_match(device_t parent, cfdata_t |
|
{ |
{ |
struct fdt_attach_args * const faa = aux; |
struct fdt_attach_args * const faa = aux; |
|
|
return of_match_compatible(faa->faa_phandle, compatible); |
return of_match_compat_data(faa->faa_phandle, compat_data); |
} |
} |
|
|
static void |
static void |
Line 240 rk_gmac_attach(device_t parent, device_t |
|
Line 335 rk_gmac_attach(device_t parent, device_t |
|
const int phandle = faa->faa_phandle; |
const int phandle = faa->faa_phandle; |
const char *phy_mode; |
const char *phy_mode; |
char intrstr[128]; |
char intrstr[128]; |
bus_addr_t addr, grf_addr; |
bus_addr_t addr; |
bus_size_t size, grf_size; |
bus_size_t size; |
u_int tx_delay, rx_delay; |
u_int tx_delay, rx_delay; |
|
|
if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { |
if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { |
Line 249 rk_gmac_attach(device_t parent, device_t |
|
Line 344 rk_gmac_attach(device_t parent, device_t |
|
return; |
return; |
} |
} |
|
|
const int grf_phandle = fdtbus_get_phandle(phandle, "rockchip,grf"); |
rk_sc->sc_type = of_search_compatible(phandle, compat_data)->data; |
if (grf_phandle == -1) { |
|
aprint_error(": couldn't get grf phandle\n"); |
rk_sc->sc_syscon = fdtbus_syscon_acquire(phandle, "rockchip,grf"); |
return; |
if (rk_sc->sc_syscon == NULL) { |
} |
aprint_error(": couldn't get grf syscon\n"); |
if (fdtbus_get_reg(grf_phandle, 0, &grf_addr, &grf_size) != 0) { |
|
aprint_error(": couldn't get grf registers\n"); |
|
return; |
|
} |
|
if (bus_space_map(faa->faa_bst, grf_addr, grf_size, 0, &rk_sc->sc_grf_bsh) != 0) { |
|
aprint_error(": couldn't map grf registers\n"); |
|
return; |
return; |
} |
} |
|
|
Line 288 rk_gmac_attach(device_t parent, device_t |
|
Line 377 rk_gmac_attach(device_t parent, device_t |
|
if (rk_gmac_reset(phandle) != 0) |
if (rk_gmac_reset(phandle) != 0) |
aprint_error_dev(self, "PHY reset failed\n"); |
aprint_error_dev(self, "PHY reset failed\n"); |
|
|
|
/* Rock64 seems to need more time for the reset to complete */ |
|
delay(100000); |
|
|
#if notyet |
#if notyet |
if (of_hasprop(phandle, "snps,force_thresh_dma_mode")) |
if (of_hasprop(phandle, "snps,force_thresh_dma_mode")) |
sc->sc_flags |= DWC_GMAC_FORCE_THRESH_DMA_MODE; |
sc->sc_flags |= DWC_GMAC_FORCE_THRESH_DMA_MODE; |
Line 299 rk_gmac_attach(device_t parent, device_t |
|
Line 391 rk_gmac_attach(device_t parent, device_t |
|
return; |
return; |
} |
} |
|
|
if (strcmp(phy_mode, "rgmii") == 0) { |
switch (rk_sc->sc_type) { |
rk3328_gmac_set_mode_rgmii(sc, tx_delay, rx_delay); |
case GMAC_RK3328: |
|
if (strcmp(phy_mode, "rgmii") == 0) { |
sc->sc_set_speed = rk3328_gmac_set_speed_rgmii; |
rk3328_gmac_set_mode_rgmii(sc, tx_delay, rx_delay); |
} else { |
|
aprint_error(": unsupported phy-mode '%s'\n", phy_mode); |
sc->sc_set_speed = rk3328_gmac_set_speed_rgmii; |
return; |
} else { |
|
aprint_error(": unsupported phy-mode '%s'\n", phy_mode); |
|
return; |
|
} |
|
break; |
|
case GMAC_RK3399: |
|
if (strcmp(phy_mode, "rgmii") == 0) { |
|
rk3399_gmac_set_mode_rgmii(sc, tx_delay, rx_delay); |
|
|
|
sc->sc_set_speed = rk3399_gmac_set_speed_rgmii; |
|
} else { |
|
aprint_error(": unsupported phy-mode '%s'\n", phy_mode); |
|
return; |
|
} |
|
break; |
} |
} |
|
|
aprint_naive("\n"); |
aprint_naive("\n"); |
aprint_normal(": GMAC\n"); |
aprint_normal(": GMAC\n"); |
|
|
|
if (dwc_gmac_attach(sc, MII_PHY_ANY, GMAC_MII_CLK_150_250M_DIV102) != 0) |
|
return; |
|
|
if (fdtbus_intr_establish(phandle, 0, IPL_NET, 0, rk_gmac_intr, sc) == NULL) { |
if (fdtbus_intr_establish(phandle, 0, IPL_NET, 0, rk_gmac_intr, sc) == NULL) { |
aprint_error_dev(self, "failed to establish interrupt on %s\n", intrstr); |
aprint_error_dev(self, "failed to establish interrupt on %s\n", intrstr); |
return; |
return; |
} |
} |
aprint_normal_dev(self, "interrupting on %s\n", intrstr); |
aprint_normal_dev(self, "interrupting on %s\n", intrstr); |
|
|
dwc_gmac_attach(sc, GMAC_MII_CLK_150_250M_DIV102); |
|
} |
} |
|
|
CFATTACH_DECL_NEW(rk_gmac, sizeof(struct rk_gmac_softc), |
CFATTACH_DECL_NEW(rk_gmac, sizeof(struct rk_gmac_softc), |