| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: sunxi_emac.c,v 1.9 2017/11/16 03:07:17 ozaki-r Exp $ */ | | 1 | /* $NetBSD: sunxi_emac.c,v 1.10 2017/11/30 21:36:11 jmcneill Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2016-2017 Jared McNeill <jmcneill@invisible.ca> | | 4 | * Copyright (c) 2016-2017 Jared McNeill <jmcneill@invisible.ca> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -23,27 +23,27 @@ | | | @@ -23,27 +23,27 @@ |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | /* | | 29 | /* |
30 | * Allwinner Gigabit Ethernet MAC (EMAC) controller | | 30 | * Allwinner Gigabit Ethernet MAC (EMAC) controller |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #include "opt_net_mpsafe.h" | | 33 | #include "opt_net_mpsafe.h" |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | __KERNEL_RCSID(0, "$NetBSD: sunxi_emac.c,v 1.9 2017/11/16 03:07:17 ozaki-r Exp $"); | | 36 | __KERNEL_RCSID(0, "$NetBSD: sunxi_emac.c,v 1.10 2017/11/30 21:36:11 jmcneill Exp $"); |
37 | | | 37 | |
38 | #include <sys/param.h> | | 38 | #include <sys/param.h> |
39 | #include <sys/bus.h> | | 39 | #include <sys/bus.h> |
40 | #include <sys/device.h> | | 40 | #include <sys/device.h> |
41 | #include <sys/intr.h> | | 41 | #include <sys/intr.h> |
42 | #include <sys/systm.h> | | 42 | #include <sys/systm.h> |
43 | #include <sys/kernel.h> | | 43 | #include <sys/kernel.h> |
44 | #include <sys/mutex.h> | | 44 | #include <sys/mutex.h> |
45 | #include <sys/callout.h> | | 45 | #include <sys/callout.h> |
46 | #include <sys/gpio.h> | | 46 | #include <sys/gpio.h> |
47 | #include <sys/cprng.h> | | 47 | #include <sys/cprng.h> |
48 | | | 48 | |
49 | #include <net/if.h> | | 49 | #include <net/if.h> |
| @@ -87,43 +87,44 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_emac.c | | | @@ -87,43 +87,44 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_emac.c |
87 | #define RX_NEXT(n) (((n) + 1) & (RX_DESC_COUNT - 1)) | | 87 | #define RX_NEXT(n) (((n) + 1) & (RX_DESC_COUNT - 1)) |
88 | | | 88 | |
89 | #define TX_MAX_SEGS 128 | | 89 | #define TX_MAX_SEGS 128 |
90 | | | 90 | |
91 | #define SOFT_RST_RETRY 1000 | | 91 | #define SOFT_RST_RETRY 1000 |
92 | #define MII_BUSY_RETRY 1000 | | 92 | #define MII_BUSY_RETRY 1000 |
93 | #define MDIO_FREQ 2500000 | | 93 | #define MDIO_FREQ 2500000 |
94 | | | 94 | |
95 | #define BURST_LEN_DEFAULT 8 | | 95 | #define BURST_LEN_DEFAULT 8 |
96 | #define RX_TX_PRI_DEFAULT 0 | | 96 | #define RX_TX_PRI_DEFAULT 0 |
97 | #define PAUSE_TIME_DEFAULT 0x400 | | 97 | #define PAUSE_TIME_DEFAULT 0x400 |
98 | | | 98 | |
99 | /* syscon EMAC clock register */ | | 99 | /* syscon EMAC clock register */ |
100 | #define EMAC_CLK_EPHY_ADDR (0x1f << 20) /* H3 */ | | 100 | #define EMAC_CLK_REG 0x30 |
101 | #define EMAC_CLK_EPHY_ADDR_SHIFT 20 | | 101 | #define EMAC_CLK_EPHY_ADDR (0x1f << 20) /* H3 */ |
102 | #define EMAC_CLK_EPHY_LED_POL (1 << 17) /* H3 */ | | 102 | #define EMAC_CLK_EPHY_ADDR_SHIFT 20 |
103 | #define EMAC_CLK_EPHY_SHUTDOWN (1 << 16) /* H3 */ | | 103 | #define EMAC_CLK_EPHY_LED_POL (1 << 17) /* H3 */ |
104 | #define EMAC_CLK_EPHY_SELECT (1 << 15) /* H3 */ | | 104 | #define EMAC_CLK_EPHY_SHUTDOWN (1 << 16) /* H3 */ |
105 | #define EMAC_CLK_RMII_EN (1 << 13) | | 105 | #define EMAC_CLK_EPHY_SELECT (1 << 15) /* H3 */ |
106 | #define EMAC_CLK_ETXDC (0x7 << 10) | | 106 | #define EMAC_CLK_RMII_EN (1 << 13) |
107 | #define EMAC_CLK_ETXDC_SHIFT 10 | | 107 | #define EMAC_CLK_ETXDC (0x7 << 10) |
108 | #define EMAC_CLK_ERXDC (0x1f << 5) | | 108 | #define EMAC_CLK_ETXDC_SHIFT 10 |
109 | #define EMAC_CLK_ERXDC_SHIFT 5 | | 109 | #define EMAC_CLK_ERXDC (0x1f << 5) |
110 | #define EMAC_CLK_PIT (0x1 << 2) | | 110 | #define EMAC_CLK_ERXDC_SHIFT 5 |
111 | #define EMAC_CLK_PIT_MII (0 << 2) | | 111 | #define EMAC_CLK_PIT (0x1 << 2) |
112 | #define EMAC_CLK_PIT_RGMII (1 << 2) | | 112 | #define EMAC_CLK_PIT_MII (0 << 2) |
113 | #define EMAC_CLK_SRC (0x3 << 0) | | 113 | #define EMAC_CLK_PIT_RGMII (1 << 2) |
114 | #define EMAC_CLK_SRC_MII (0 << 0) | | 114 | #define EMAC_CLK_SRC (0x3 << 0) |
115 | #define EMAC_CLK_SRC_EXT_RGMII (1 << 0) | | 115 | #define EMAC_CLK_SRC_MII (0 << 0) |
116 | #define EMAC_CLK_SRC_RGMII (2 << 0) | | 116 | #define EMAC_CLK_SRC_EXT_RGMII (1 << 0) |
| | | 117 | #define EMAC_CLK_SRC_RGMII (2 << 0) |
117 | | | 118 | |
118 | /* Burst length of RX and TX DMA transfers */ | | 119 | /* Burst length of RX and TX DMA transfers */ |
119 | static int sunxi_emac_burst_len = BURST_LEN_DEFAULT; | | 120 | static int sunxi_emac_burst_len = BURST_LEN_DEFAULT; |
120 | | | 121 | |
121 | /* RX / TX DMA priority. If 1, RX DMA has priority over TX DMA. */ | | 122 | /* RX / TX DMA priority. If 1, RX DMA has priority over TX DMA. */ |
122 | static int sunxi_emac_rx_tx_pri = RX_TX_PRI_DEFAULT; | | 123 | static int sunxi_emac_rx_tx_pri = RX_TX_PRI_DEFAULT; |
123 | | | 124 | |
124 | /* Pause time field in the transmitted control frame */ | | 125 | /* Pause time field in the transmitted control frame */ |
125 | static int sunxi_emac_pause_time = PAUSE_TIME_DEFAULT; | | 126 | static int sunxi_emac_pause_time = PAUSE_TIME_DEFAULT; |
126 | | | 127 | |
127 | enum sunxi_emac_type { | | 128 | enum sunxi_emac_type { |
128 | EMAC_A83T = 1, | | 129 | EMAC_A83T = 1, |
129 | EMAC_H3, | | 130 | EMAC_H3, |
| @@ -879,26 +880,47 @@ sunxi_emac_ioctl(struct ifnet *ifp, u_lo | | | @@ -879,26 +880,47 @@ sunxi_emac_ioctl(struct ifnet *ifp, u_lo |
879 | sunxi_emac_setup_rxfilter(sc); | | 880 | sunxi_emac_setup_rxfilter(sc); |
880 | EMAC_UNLOCK(sc); | | 881 | EMAC_UNLOCK(sc); |
881 | } | | 882 | } |
882 | break; | | 883 | break; |
883 | } | | 884 | } |
884 | | | 885 | |
885 | #ifndef EMAC_MPSAFE | | 886 | #ifndef EMAC_MPSAFE |
886 | splx(s); | | 887 | splx(s); |
887 | #endif | | 888 | #endif |
888 | | | 889 | |
889 | return error; | | 890 | return error; |
890 | } | | 891 | } |
891 | | | 892 | |
| | | 893 | static bool |
| | | 894 | sunxi_emac_has_internal_phy(struct sunxi_emac_softc *sc) |
| | | 895 | { |
| | | 896 | const char * mdio_internal_compat[] = { |
| | | 897 | "allwinner,sun8i-h3-mdio-internal", |
| | | 898 | NULL |
| | | 899 | }; |
| | | 900 | int phy; |
| | | 901 | |
| | | 902 | /* Non-standard property, for compatible with old dts files */ |
| | | 903 | if (of_hasprop(sc->phandle, "allwinner,use-internal-phy")) |
| | | 904 | return true; |
| | | 905 | |
| | | 906 | phy = fdtbus_get_phandle(sc->phandle, "phy-handle"); |
| | | 907 | if (phy == -1) |
| | | 908 | return false; |
| | | 909 | |
| | | 910 | /* For internal PHY, check compatible string of parent node */ |
| | | 911 | return of_compatible(OF_parent(phy), mdio_internal_compat) >= 0; |
| | | 912 | } |
| | | 913 | |
892 | static int | | 914 | static int |
893 | sunxi_emac_setup_phy(struct sunxi_emac_softc *sc) | | 915 | sunxi_emac_setup_phy(struct sunxi_emac_softc *sc) |
894 | { | | 916 | { |
895 | uint32_t reg, tx_delay, rx_delay; | | 917 | uint32_t reg, tx_delay, rx_delay; |
896 | const char *phy_type; | | 918 | const char *phy_type; |
897 | | | 919 | |
898 | phy_type = fdtbus_get_string(sc->phandle, "phy-mode"); | | 920 | phy_type = fdtbus_get_string(sc->phandle, "phy-mode"); |
899 | if (phy_type == NULL) | | 921 | if (phy_type == NULL) |
900 | return 0; | | 922 | return 0; |
901 | | | 923 | |
902 | aprint_debug_dev(sc->dev, "PHY type: %s\n", phy_type); | | 924 | aprint_debug_dev(sc->dev, "PHY type: %s\n", phy_type); |
903 | | | 925 | |
904 | reg = SYSCONRD4(sc, 0); | | 926 | reg = SYSCONRD4(sc, 0); |
| @@ -911,27 +933,27 @@ sunxi_emac_setup_phy(struct sunxi_emac_s | | | @@ -911,27 +933,27 @@ sunxi_emac_setup_phy(struct sunxi_emac_s |
911 | else | | 933 | else |
912 | reg |= EMAC_CLK_PIT_MII | EMAC_CLK_SRC_MII; | | 934 | reg |= EMAC_CLK_PIT_MII | EMAC_CLK_SRC_MII; |
913 | | | 935 | |
914 | if (of_getprop_uint32(sc->phandle, "tx-delay", &tx_delay) == 0) { | | 936 | if (of_getprop_uint32(sc->phandle, "tx-delay", &tx_delay) == 0) { |
915 | reg &= ~EMAC_CLK_ETXDC; | | 937 | reg &= ~EMAC_CLK_ETXDC; |
916 | reg |= (tx_delay << EMAC_CLK_ETXDC_SHIFT); | | 938 | reg |= (tx_delay << EMAC_CLK_ETXDC_SHIFT); |
917 | } | | 939 | } |
918 | if (of_getprop_uint32(sc->phandle, "rx-delay", &rx_delay) == 0) { | | 940 | if (of_getprop_uint32(sc->phandle, "rx-delay", &rx_delay) == 0) { |
919 | reg &= ~EMAC_CLK_ERXDC; | | 941 | reg &= ~EMAC_CLK_ERXDC; |
920 | reg |= (rx_delay << EMAC_CLK_ERXDC_SHIFT); | | 942 | reg |= (rx_delay << EMAC_CLK_ERXDC_SHIFT); |
921 | } | | 943 | } |
922 | | | 944 | |
923 | if (sc->type == EMAC_H3) { | | 945 | if (sc->type == EMAC_H3) { |
924 | if (of_hasprop(sc->phandle, "allwinner,use-internal-phy")) { | | 946 | if (sunxi_emac_has_internal_phy(sc)) { |
925 | reg |= EMAC_CLK_EPHY_SELECT; | | 947 | reg |= EMAC_CLK_EPHY_SELECT; |
926 | reg &= ~EMAC_CLK_EPHY_SHUTDOWN; | | 948 | reg &= ~EMAC_CLK_EPHY_SHUTDOWN; |
927 | if (of_hasprop(sc->phandle, | | 949 | if (of_hasprop(sc->phandle, |
928 | "allwinner,leds-active-low")) | | 950 | "allwinner,leds-active-low")) |
929 | reg |= EMAC_CLK_EPHY_LED_POL; | | 951 | reg |= EMAC_CLK_EPHY_LED_POL; |
930 | else | | 952 | else |
931 | reg &= ~EMAC_CLK_EPHY_LED_POL; | | 953 | reg &= ~EMAC_CLK_EPHY_LED_POL; |
932 | | | 954 | |
933 | /* Set internal PHY addr to 1 */ | | 955 | /* Set internal PHY addr to 1 */ |
934 | reg &= ~EMAC_CLK_EPHY_ADDR; | | 956 | reg &= ~EMAC_CLK_EPHY_ADDR; |
935 | reg |= (1 << EMAC_CLK_EPHY_ADDR_SHIFT); | | 957 | reg |= (1 << EMAC_CLK_EPHY_ADDR_SHIFT); |
936 | } else { | | 958 | } else { |
937 | reg &= ~EMAC_CLK_EPHY_SELECT; | | 959 | reg &= ~EMAC_CLK_EPHY_SELECT; |
| @@ -1252,35 +1274,51 @@ sunxi_emac_setup_dma(struct sunxi_emac_s | | | @@ -1252,35 +1274,51 @@ sunxi_emac_setup_dma(struct sunxi_emac_s |
1252 | | | 1274 | |
1253 | /* Write transmit and receive descriptor base address registers */ | | 1275 | /* Write transmit and receive descriptor base address registers */ |
1254 | WR4(sc, EMAC_TX_DMA_LIST, sc->tx.desc_ring_paddr); | | 1276 | WR4(sc, EMAC_TX_DMA_LIST, sc->tx.desc_ring_paddr); |
1255 | WR4(sc, EMAC_RX_DMA_LIST, sc->rx.desc_ring_paddr); | | 1277 | WR4(sc, EMAC_RX_DMA_LIST, sc->rx.desc_ring_paddr); |
1256 | | | 1278 | |
1257 | return 0; | | 1279 | return 0; |
1258 | } | | 1280 | } |
1259 | | | 1281 | |
1260 | static int | | 1282 | static int |
1261 | sunxi_emac_get_resources(struct sunxi_emac_softc *sc) | | 1283 | sunxi_emac_get_resources(struct sunxi_emac_softc *sc) |
1262 | { | | 1284 | { |
1263 | const int phandle = sc->phandle; | | 1285 | const int phandle = sc->phandle; |
1264 | bus_addr_t addr, size; | | 1286 | bus_addr_t addr, size; |
1265 | u_int n; | | | |
1266 | | | 1287 | |
1267 | /* Map registers */ | | 1288 | /* Map EMAC registers */ |
1268 | for (n = 0; n < _RES_NITEMS; n++) { | | 1289 | if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) |
1269 | if (fdtbus_get_reg(phandle, n, &addr, &size) != 0) | | 1290 | return ENXIO; |
| | | 1291 | if (bus_space_map(sc->bst, addr, size, 0, &sc->bsh[_RES_EMAC]) != 0) |
| | | 1292 | return ENXIO; |
| | | 1293 | |
| | | 1294 | /* Map SYSCON registers */ |
| | | 1295 | if (of_hasprop(phandle, "syscon")) { |
| | | 1296 | const int syscon_phandle = fdtbus_get_phandle(phandle, |
| | | 1297 | "syscon"); |
| | | 1298 | if (syscon_phandle == -1) |
| | | 1299 | return ENXIO; |
| | | 1300 | if (fdtbus_get_reg(syscon_phandle, 0, &addr, &size) != 0) |
1270 | return ENXIO; | | 1301 | return ENXIO; |
1271 | if (bus_space_map(sc->bst, addr, size, 0, &sc->bsh[n]) != 0) | | 1302 | if (size < EMAC_CLK_REG + 4) |
| | | 1303 | return ENXIO; |
| | | 1304 | addr += EMAC_CLK_REG; |
| | | 1305 | size -= EMAC_CLK_REG; |
| | | 1306 | } else { |
| | | 1307 | if (fdtbus_get_reg(phandle, 1, &addr, &size) != 0) |
1272 | return ENXIO; | | 1308 | return ENXIO; |
1273 | } | | 1309 | } |
| | | 1310 | if (bus_space_map(sc->bst, addr, size, 0, &sc->bsh[_RES_SYSCON]) != 0) |
| | | 1311 | return ENXIO; |
1274 | | | 1312 | |
1275 | /* Get clocks and resets. "ahb" is required, "ephy" is optional. */ | | 1313 | /* Get clocks and resets. "ahb" is required, "ephy" is optional. */ |
1276 | | | 1314 | |
1277 | if ((sc->clk_ahb = fdtbus_clock_get(phandle, "ahb")) == NULL) | | 1315 | if ((sc->clk_ahb = fdtbus_clock_get(phandle, "ahb")) == NULL) |
1278 | return ENXIO; | | 1316 | return ENXIO; |
1279 | sc->clk_ephy = fdtbus_clock_get(phandle, "ephy"); | | 1317 | sc->clk_ephy = fdtbus_clock_get(phandle, "ephy"); |
1280 | | | 1318 | |
1281 | if ((sc->rst_ahb = fdtbus_reset_get(phandle, "ahb")) == NULL) | | 1319 | if ((sc->rst_ahb = fdtbus_reset_get(phandle, "ahb")) == NULL) |
1282 | return ENXIO; | | 1320 | return ENXIO; |
1283 | sc->rst_ephy = fdtbus_reset_get(phandle, "ephy"); | | 1321 | sc->rst_ephy = fdtbus_reset_get(phandle, "ephy"); |
1284 | | | 1322 | |
1285 | /* Regulator is optional */ | | 1323 | /* Regulator is optional */ |
1286 | sc->reg_phy = fdtbus_regulator_acquire(phandle, "phy-supply"); | | 1324 | sc->reg_phy = fdtbus_regulator_acquire(phandle, "phy-supply"); |