diff options
Diffstat (limited to 'sys/arm')
81 files changed, 3059 insertions, 294 deletions
diff --git a/sys/arm/allwinner/a10/a10_intc.c b/sys/arm/allwinner/a10/a10_intc.c index 7bd8e80..31e6ef4 100644 --- a/sys/arm/allwinner/a10/a10_intc.c +++ b/sys/arm/allwinner/a10/a10_intc.c @@ -298,14 +298,18 @@ static int a10_intr_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { + struct intr_map_data_fdt *daf; struct a10_aintc_softc *sc; - if (data->type != INTR_MAP_DATA_FDT || data->fdt.ncells != 1 || - data->fdt.cells[0] >= A10_INTR_MAX_NIRQS) + if (data->type != INTR_MAP_DATA_FDT) + return (ENOTSUP); + + daf = (struct intr_map_data_fdt *)data; + if (daf->ncells != 1 || daf->cells[0] >= A10_INTR_MAX_NIRQS) return (EINVAL); sc = device_get_softc(dev); - *isrcp = &sc->isrcs[data->fdt.cells[0]].isrc; + *isrcp = &sc->isrcs[daf->cells[0]].isrc; return (0); } diff --git a/sys/arm/allwinner/a10_ehci.c b/sys/arm/allwinner/a10_ehci.c index c325d60..4a9ee80 100644 --- a/sys/arm/allwinner/a10_ehci.c +++ b/sys/arm/allwinner/a10_ehci.c @@ -112,6 +112,7 @@ static struct ofw_compat_data compat_data[] = { { "allwinner,sun4i-a10-ehci", (uintptr_t)&a10_ehci_conf }, { "allwinner,sun6i-a31-ehci", (uintptr_t)&a31_ehci_conf }, { "allwinner,sun7i-a20-ehci", (uintptr_t)&a10_ehci_conf }, + { "allwinner,sun8i-a83t-ehci", (uintptr_t)&a31_ehci_conf }, { NULL, (uintptr_t)NULL } }; diff --git a/sys/arm/allwinner/a10_gpio.c b/sys/arm/allwinner/a10_gpio.c index 4e6e612..079e715 100644 --- a/sys/arm/allwinner/a10_gpio.c +++ b/sys/arm/allwinner/a10_gpio.c @@ -99,6 +99,12 @@ extern const struct allwinner_padconf a31s_padconf; extern const struct allwinner_padconf a31_r_padconf; #endif +/* Defined in a83t_padconf.c */ +#ifdef SOC_ALLWINNER_A83T +extern const struct allwinner_padconf a83t_padconf; +extern const struct allwinner_padconf a83t_r_padconf; +#endif + static struct ofw_compat_data compat_data[] = { #ifdef SOC_ALLWINNER_A10 {"allwinner,sun4i-a10-pinctrl", (uintptr_t)&a10_padconf}, @@ -115,6 +121,10 @@ static struct ofw_compat_data compat_data[] = { #if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S) {"allwinner,sun6i-a31-r-pinctrl", (uintptr_t)&a31_r_padconf}, #endif +#ifdef SOC_ALLWINNER_A83T + {"allwinner,sun8i-a83t-pinctrl", (uintptr_t)&a83t_padconf}, + {"allwinner,sun8i-a83t-r-pinctrl", (uintptr_t)&a83t_r_padconf}, +#endif {NULL, 0} }; diff --git a/sys/arm/allwinner/a83t/a83t_padconf.c b/sys/arm/allwinner/a83t/a83t_padconf.c new file mode 100644 index 0000000..bbf638e --- /dev/null +++ b/sys/arm/allwinner/a83t/a83t_padconf.c @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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 + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/types.h> + +#include <arm/allwinner/allwinner_pinctrl.h> + +#ifdef SOC_ALLWINNER_A83T + +static const struct allwinner_pins a83t_pins[] = { + { "PB0", 1, 0, { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } }, + { "PB1", 1, 1, { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } }, + { "PB2", 1, 2, { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } }, + { "PB3", 1, 3, { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } }, + { "PB4", 1, 4, { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } }, + { "PB5", 1, 5, { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } }, + { "PB6", 1, 6, { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } }, + { "PB7", 1, 7, { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } }, + { "PB8", 1, 8, { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } }, + { "PB9", 1, 9, { "gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, "eint" } }, + { "PB10", 1, 10, { "gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, "eint" } }, + + { "PC0", 2, 0, { "gpio_in", "gpio_out", "nand", "spi0" } }, + { "PC1", 2, 1, { "gpio_in", "gpio_out", "nand", "spi0" } }, + { "PC2", 2, 2, { "gpio_in", "gpio_out", "nand", "spi0" } }, + { "PC3", 2, 3, { "gpio_in", "gpio_out", "nand", "spi0" } }, + { "PC4", 2, 4, { "gpio_in", "gpio_out", "nand" } }, + { "PC5", 2, 5, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC6", 2, 6, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC7", 2, 7, { "gpio_in", "gpio_out", "nand" } }, + { "PC8", 2, 8, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC9", 2, 9, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC10", 2, 10, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC11", 2, 11, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC12", 2, 12, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC13", 2, 13, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC14", 2, 14, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC15", 2, 15, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC16", 2, 16, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC17", 2, 17, { "gpio_in", "gpio_out", "nand" } }, + { "PC18", 2, 18, { "gpio_in", "gpio_out", "nand" } }, + + { "PD2", 3, 2, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD3", 3, 3, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD4", 3, 4, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD5", 3, 5, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD6", 3, 6, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD7", 3, 7, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD10", 3, 10, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD11", 3, 11, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD12", 3, 12, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD13", 3, 13, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD14", 3, 14, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD15", 3, 15, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD18", 3, 18, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD19", 3, 19, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD20", 3, 20, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD21", 3, 21, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD22", 3, 22, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD23", 3, 23, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD24", 3, 24, { "gpio_in", "gpio_out", "lcd", "lvds" } }, + { "PD25", 3, 25, { "gpio_in", "gpio_out", "lcd", "lvds" } }, + { "PD26", 3, 26, { "gpio_in", "gpio_out", "lcd", "lvds" } }, + { "PD27", 3, 27, { "gpio_in", "gpio_out", "lcd", "lvds" } }, + { "PD28", 3, 28, { "gpio_in", "gpio_out", "pwm" } }, + { "PD29", 3, 29, { "gpio_in", "gpio_out" } }, + + { "PE0", 4, 0, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE1", 4, 1, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE2", 4, 2, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE3", 4, 3, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE4", 4, 4, { "gpio_in", "gpio_out", "csi" } }, + { "PE5", 4, 5, { "gpio_in", "gpio_out", "csi" } }, + { "PE6", 4, 6, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE7", 4, 7, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE8", 4, 8, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE9", 4, 9, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE10", 4, 10, { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } }, + { "PE11", 4, 11, { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } }, + { "PE12", 4, 12, { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } }, + { "PE13", 4, 13, { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } }, + { "PE14", 4, 14, { "gpio_in", "gpio_out", "csi", "twi2" } }, + { "PE15", 4, 15, { "gpio_in", "gpio_out", "csi", "twi2" } }, + { "PE16", 4, 16, { "gpio_in", "gpio_out" } }, + { "PE17", 4, 17, { "gpio_in", "gpio_out" } }, + { "PE18", 4, 18, { "gpio_in", "gpio_out", NULL, "owa" } }, + { "PE19", 4, 19, { "gpio_in", "gpio_out" } }, + + { "PF0", 5, 0, { "gpio_in", "gpio_out", "mmc0", "jtag" } }, + { "PF1", 5, 1, { "gpio_in", "gpio_out", "mmc0", "jtag" } }, + { "PF2", 5, 2, { "gpio_in", "gpio_out", "mmc0", "uart0" } }, + { "PF3", 5, 3, { "gpio_in", "gpio_out", "mmc0", "jtag" } }, + { "PF4", 5, 4, { "gpio_in", "gpio_out", "mmc0", "uart0" } }, + { "PF5", 5, 5, { "gpio_in", "gpio_out", "mmc0", "jtag" } }, + { "PF6", 5, 6, { "gpio_in", "gpio_out" } }, + + { "PG0", 6, 0, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG1", 6, 1, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG2", 6, 2, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG3", 6, 3, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG4", 6, 4, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG5", 6, 5, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG6", 6, 6, { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } }, + { "PG7", 6, 7, { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } }, + { "PG8", 6, 8, { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } }, + { "PG9", 6, 9, { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } }, + { "PG10", 6, 10, { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } }, + { "PG11", 6, 11, { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } }, + { "PG12", 6, 12, { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } }, + { "PG13", 6, 13, { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } }, + + { "PH0", 7, 0, { "gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, "eint" } }, + { "PH1", 7, 1, { "gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, "eint" } }, + { "PH2", 7, 2, { "gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, "eint" } }, + { "PH3", 7, 3, { "gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, "eint" } }, + { "PH4", 7, 4, { "gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, "eint" } }, + { "PH5", 7, 5, { "gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, "eint" } }, + { "PH6", 7, 6, { "gpio_in", "gpio_out", "hdmiddc", NULL, NULL, NULL, "eint" } }, + { "PH7", 7, 7, { "gpio_in", "gpio_out", "hdmiddc", NULL, NULL, NULL, "eint" } }, + { "PH8", 7, 8, { "gpio_in", "gpio_out", "hdmiddc", NULL, NULL, NULL, "eint" } }, + { "PH9", 7, 9, { "gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "eint" } }, + { "PH10", 7, 10, { "gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "eint" } }, + { "PH11", 7, 11, { "gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "eint" } }, +}; + +const struct allwinner_padconf a83t_padconf = { + .npins = nitems(a83t_pins), + .pins = a83t_pins, +}; + +#endif /* !SOC_ALLWINNER_A83T */ diff --git a/sys/arm/allwinner/a83t/a83t_r_padconf.c b/sys/arm/allwinner/a83t/a83t_r_padconf.c new file mode 100644 index 0000000..e463745 --- /dev/null +++ b/sys/arm/allwinner/a83t/a83t_r_padconf.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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 + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/types.h> + +#include <arm/allwinner/allwinner_pinctrl.h> + +#ifdef SOC_ALLWINNER_A83T + +static const struct allwinner_pins a83t_r_pins[] = { + { "PL0", 0, 0, { "gpio_in", "gpio_out", "s_rsb", "s_i2c", NULL, NULL, "eint" } }, + { "PL1", 0, 1, { "gpio_in", "gpio_out", "s_rsb", "s_i2c", NULL, NULL, "eint" } }, + { "PL2", 0, 2, { "gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, "eint" } }, + { "PL3", 0, 3, { "gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, "eint" } }, + { "PL4", 0, 4, { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } }, + { "PL5", 0, 5, { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } }, + { "PL6", 0, 6, { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } }, + { "PL7", 0, 7, { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } }, + { "PL8", 0, 8, { "gpio_in", "gpio_out", "s_i2c", NULL, NULL, NULL, "eint" } }, + { "PL9", 0, 9, { "gpio_in", "gpio_out", "s_i2c", NULL, NULL, NULL, "eint" } }, + { "PL10", 0, 10, { "gpio_in", "gpio_out", "s_pwm", NULL, NULL, NULL, "eint" } }, + { "PL11", 0, 11, { "gpio_in", "gpio_out", NULL, NULL, NULL, "eint" } }, + { "PL12", 0, 12, { "gpio_in", "gpio_out", "s_cir", NULL, NULL, NULL, "eint" } }, +}; + +const struct allwinner_padconf a83t_r_padconf = { + .npins = nitems(a83t_r_pins), + .pins = a83t_r_pins, +}; + +#endif /* !SOC_ALLWINNER_A83T */ diff --git a/sys/arm/allwinner/a83t/files.a83t b/sys/arm/allwinner/a83t/files.a83t new file mode 100644 index 0000000..45334a0 --- /dev/null +++ b/sys/arm/allwinner/a83t/files.a83t @@ -0,0 +1,4 @@ +# $FreeBSD$ + +arm/allwinner/a83t/a83t_padconf.c standard +arm/allwinner/a83t/a83t_r_padconf.c standard diff --git a/sys/arm/allwinner/a83t/std.a83t b/sys/arm/allwinner/a83t/std.a83t new file mode 100644 index 0000000..06b1ed4 --- /dev/null +++ b/sys/arm/allwinner/a83t/std.a83t @@ -0,0 +1,15 @@ +# Allwinner A83T common options +#$FreeBSD$ + +cpu CPU_CORTEXA +machine arm armv6 +makeoptions CONF_CFLAGS="-march=armv7a" + +makeoptions KERNVIRTADDR=0xc0200000 +options KERNVIRTADDR=0xc0200000 + +options IPI_IRQ_START=0 +options IPI_IRQ_END=15 + +files "../allwinner/files.allwinner" +files "../allwinner/a83t/files.a83t" diff --git a/sys/arm/allwinner/allwinner_machdep.c b/sys/arm/allwinner/allwinner_machdep.c index e5c8eb8..7916441 100644 --- a/sys/arm/allwinner/allwinner_machdep.c +++ b/sys/arm/allwinner/allwinner_machdep.c @@ -94,6 +94,15 @@ a31s_attach(platform_t plat) return (0); } +static int +a83t_attach(platform_t plat) +{ + soc_type = ALLWINNERSOC_A83T; + soc_family = ALLWINNERSOC_SUN8I; + + return (0); +} + static vm_offset_t allwinner_lastaddr(platform_t plat) { @@ -196,6 +205,21 @@ static platform_method_t a31s_methods[] = { FDT_PLATFORM_DEF(a31s, "a31s", 0, "allwinner,sun6i-a31s", 200); #endif +#if defined(SOC_ALLWINNER_A83T) +static platform_method_t a83t_methods[] = { + PLATFORMMETHOD(platform_attach, a83t_attach), + PLATFORMMETHOD(platform_lastaddr, allwinner_lastaddr), + PLATFORMMETHOD(platform_devmap_init, allwinner_devmap_init), + +#ifdef SMP + PLATFORMMETHOD(platform_mp_start_ap, a83t_mp_start_ap), + PLATFORMMETHOD(platform_mp_setmaxid, aw_mp_setmaxid), +#endif + PLATFORMMETHOD_END, +}; +FDT_PLATFORM_DEF(a83t, "a83t", 0, "allwinner,sun8i-a83t", 200); +#endif + u_int allwinner_soc_type(void) { diff --git a/sys/arm/allwinner/allwinner_machdep.h b/sys/arm/allwinner/allwinner_machdep.h index c640494..91c97ac 100644 --- a/sys/arm/allwinner/allwinner_machdep.h +++ b/sys/arm/allwinner/allwinner_machdep.h @@ -36,11 +36,13 @@ #define ALLWINNERSOC_A20 0x20000000 #define ALLWINNERSOC_A31 0x31000000 #define ALLWINNERSOC_A31S 0x31000001 +#define ALLWINNERSOC_A83T 0x83000000 #define ALLWINNERSOC_SUN4I 0x40000000 #define ALLWINNERSOC_SUN5I 0x50000000 #define ALLWINNERSOC_SUN6I 0x60000000 #define ALLWINNERSOC_SUN7I 0x70000000 +#define ALLWINNERSOC_SUN8I 0x80000000 u_int allwinner_soc_type(void); u_int allwinner_soc_family(void); diff --git a/sys/arm/allwinner/aw_ccu.c b/sys/arm/allwinner/aw_ccu.c index d2ce774..a8342ca 100644 --- a/sys/arm/allwinner/aw_ccu.c +++ b/sys/arm/allwinner/aw_ccu.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <dev/fdt/simplebus.h> +#include <dev/fdt/fdt_common.h> #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> @@ -53,40 +54,74 @@ __FBSDID("$FreeBSD$"); #define CCU_BASE 0x01c20000 #define CCU_SIZE 0x400 +#define PRCM_BASE 0x01f01400 +#define PRCM_SIZE 0x200 + +#define SYSCTRL_BASE 0x01c00000 +#define SYSCTRL_SIZE 0x34 + struct aw_ccu_softc { struct simplebus_softc sc; bus_space_tag_t bst; - bus_space_handle_t bsh; + bus_space_handle_t ccu_bsh; + bus_space_handle_t prcm_bsh; + bus_space_handle_t sysctrl_bsh; struct mtx mtx; + int flags; }; +#define CLOCK_CCU (1 << 0) +#define CLOCK_PRCM (1 << 1) +#define CLOCK_SYSCTRL (1 << 2) + static struct ofw_compat_data compat_data[] = { - { "allwinner,sun4i-a10", 1 }, - { "allwinner,sun7i-a20", 1 }, - { "allwinner,sun6i-a31", 1 }, - { "allwinner,sun6i-a31s", 1 }, + { "allwinner,sun4i-a10", CLOCK_CCU }, + { "allwinner,sun7i-a20", CLOCK_CCU }, + { "allwinner,sun6i-a31", CLOCK_CCU }, + { "allwinner,sun6i-a31s", CLOCK_CCU }, + { "allwinner,sun8i-a83t", CLOCK_CCU|CLOCK_PRCM|CLOCK_SYSCTRL }, { NULL, 0 } }; static int -aw_ccu_check_addr(bus_addr_t addr) +aw_ccu_check_addr(struct aw_ccu_softc *sc, bus_addr_t addr, + bus_space_handle_t *pbsh, bus_size_t *poff) { - if (addr < CCU_BASE || addr >= (CCU_BASE + CCU_SIZE)) - return (EINVAL); - return (0); + if (addr >= CCU_BASE && addr < (CCU_BASE + CCU_SIZE) && + (sc->flags & CLOCK_CCU) != 0) { + *poff = addr - CCU_BASE; + *pbsh = sc->ccu_bsh; + return (0); + } + if (addr >= PRCM_BASE && addr < (PRCM_BASE + PRCM_SIZE) && + (sc->flags & CLOCK_PRCM) != 0) { + *poff = addr - PRCM_BASE; + *pbsh = sc->prcm_bsh; + return (0); + } + if (addr >= SYSCTRL_BASE && addr < (SYSCTRL_BASE + SYSCTRL_SIZE) && + (sc->flags & CLOCK_SYSCTRL) != 0) { + *poff = addr - SYSCTRL_BASE; + *pbsh = sc->sysctrl_bsh; + return (0); + } + return (EINVAL); } static int aw_ccu_write_4(device_t dev, bus_addr_t addr, uint32_t val) { struct aw_ccu_softc *sc; + bus_space_handle_t bsh; + bus_size_t reg; - if (aw_ccu_check_addr(addr) != 0) + sc = device_get_softc(dev); + + if (aw_ccu_check_addr(sc, addr, &bsh, ®) != 0) return (EINVAL); - sc = device_get_softc(dev); mtx_assert(&sc->mtx, MA_OWNED); - bus_space_write_4(sc->bst, sc->bsh, addr - CCU_BASE, val); + bus_space_write_4(sc->bst, bsh, reg, val); return (0); } @@ -95,13 +130,16 @@ static int aw_ccu_read_4(device_t dev, bus_addr_t addr, uint32_t *val) { struct aw_ccu_softc *sc; + bus_space_handle_t bsh; + bus_size_t reg; + + sc = device_get_softc(dev); - if (aw_ccu_check_addr(addr) != 0) + if (aw_ccu_check_addr(sc, addr, &bsh, ®) != 0) return (EINVAL); - sc = device_get_softc(dev); mtx_assert(&sc->mtx, MA_OWNED); - *val = bus_space_read_4(sc->bst, sc->bsh, addr - CCU_BASE); + *val = bus_space_read_4(sc->bst, bsh, reg); return (0); } @@ -110,17 +148,20 @@ static int aw_ccu_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) { struct aw_ccu_softc *sc; + bus_space_handle_t bsh; + bus_size_t reg; uint32_t val; - if (aw_ccu_check_addr(addr) != 0) + sc = device_get_softc(dev); + + if (aw_ccu_check_addr(sc, addr, &bsh, ®) != 0) return (EINVAL); - sc = device_get_softc(dev); mtx_assert(&sc->mtx, MA_OWNED); - val = bus_space_read_4(sc->bst, sc->bsh, addr - CCU_BASE); + val = bus_space_read_4(sc->bst, bsh, reg); val &= ~clr; val |= set; - bus_space_write_4(sc->bst, sc->bsh, addr - CCU_BASE, val); + bus_space_write_4(sc->bst, bsh, reg, val); return (0); } @@ -143,20 +184,32 @@ aw_ccu_device_unlock(device_t dev) mtx_unlock(&sc->mtx); } +static const struct ofw_compat_data * +aw_ccu_search_compatible(void) +{ + const struct ofw_compat_data *compat; + phandle_t root; + + root = OF_finddevice("/"); + for (compat = compat_data; compat_data->ocd_str != NULL; compat++) + if (fdt_is_compatible(root, compat->ocd_str)) + break; + + return (compat); +} + static int aw_ccu_probe(device_t dev) { const char *name; - device_t pdev; name = ofw_bus_get_name(dev); if (name == NULL || strcmp(name, "clocks") != 0) return (ENXIO); - pdev = device_get_parent(dev); - if (ofw_bus_search_compatible(pdev, compat_data)->ocd_data == 0) - return (0); + if (aw_ccu_search_compatible()->ocd_data == 0) + return (ENXIO); device_set_desc(dev, "Allwinner Clock Control Unit"); return (BUS_PROBE_SPECIFIC); @@ -175,15 +228,37 @@ aw_ccu_attach(device_t dev) simplebus_init(dev, node); + sc->flags = aw_ccu_search_compatible()->ocd_data; + /* - * Map CCU registers. The DT doesn't have a "reg" property for the - * /clocks node and child nodes have conflicting "reg" properties. + * Map registers. The DT doesn't have a "reg" property + * for the /clocks node and child nodes have conflicting "reg" + * properties. */ sc->bst = bus_get_bus_tag(dev); - error = bus_space_map(sc->bst, CCU_BASE, CCU_SIZE, 0, &sc->bsh); - if (error != 0) { - device_printf(dev, "couldn't map CCU: %d\n", error); - return (error); + if (sc->flags & CLOCK_CCU) { + error = bus_space_map(sc->bst, CCU_BASE, CCU_SIZE, 0, + &sc->ccu_bsh); + if (error != 0) { + device_printf(dev, "couldn't map CCU: %d\n", error); + return (error); + } + } + if (sc->flags & CLOCK_PRCM) { + error = bus_space_map(sc->bst, PRCM_BASE, PRCM_SIZE, 0, + &sc->prcm_bsh); + if (error != 0) { + device_printf(dev, "couldn't map PRCM: %d\n", error); + return (error); + } + } + if (sc->flags & CLOCK_SYSCTRL) { + error = bus_space_map(sc->bst, SYSCTRL_BASE, SYSCTRL_SIZE, 0, + &sc->sysctrl_bsh); + if (error != 0) { + device_printf(dev, "couldn't map SYSCTRL: %d\n", error); + return (error); + } } mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); diff --git a/sys/arm/allwinner/aw_mp.c b/sys/arm/allwinner/aw_mp.c index 9e46f2d..ce0dddd 100644 --- a/sys/arm/allwinner/aw_mp.c +++ b/sys/arm/allwinner/aw_mp.c @@ -55,6 +55,9 @@ __FBSDID("$FreeBSD$"); #define CPUCFG_SIZE 0x400 #define PRCM_BASE 0x01f01400 #define PRCM_SIZE 0x800 +/* Register for multi-cluster SoC */ +#define CPUXCFG_BASE 0x01700000 +#define CPUXCFG_SIZE 0x400 #define CPU_OFFSET 0x40 #define CPU_OFFSET_CTL 0x04 @@ -80,6 +83,14 @@ __FBSDID("$FreeBSD$"); #define CPUCFG_DBGCTL0 0x1e0 #define CPUCFG_DBGCTL1 0x1e4 +#define CPUS_CL_RST(cl) (0x30 + (cluster) * 0x4) +#define CPUX_CL_CTRL0(cl) (0x0 + (cluster) * 0x10) +#define CPUX_CL_CTRL1(cl) (0x4 + (cluster) * 0x10) +#define CPUX_CL_CPU_STATUS(cl) (0x30 + (cluster) * 0x4) +#define CPUX_CL_RST(cl) (0x80 + (cluster) * 0x4) +#define PRCM_CL_PWROFF(cl) (0x100 + (cluster) * 0x4) +#define PRCM_CL_PWR_CLAMP(cl, cpu) (0x140 + (cluster) * 0x4 + (cpu) * 0x4) + void aw_mp_setmaxid(platform_t plat) { @@ -202,3 +213,89 @@ a31_mp_start_ap(platform_t plat) bus_space_unmap(fdtbus_bs_tag, cpucfg, CPUCFG_SIZE); bus_space_unmap(fdtbus_bs_tag, prcm, PRCM_SIZE); } + +static void +aw_mc_mp_start_cpu(bus_space_handle_t cpuscfg, bus_space_handle_t cpuxcfg, + bus_space_handle_t prcm, int cluster, int cpu) +{ + uint32_t val; + int i; + + /* Assert core reset */ + val = bus_space_read_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_RST(cluster)); + val &= ~(1 << cpu); + bus_space_write_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_RST(cluster), val); + + /* Assert power-on reset */ + val = bus_space_read_4(fdtbus_bs_tag, cpuscfg, CPUS_CL_RST(cluster)); + val &= ~(1 << cpu); + bus_space_write_4(fdtbus_bs_tag, cpuscfg, CPUS_CL_RST(cluster), val); + + /* Disable automatic L1 cache invalidate at reset */ + val = bus_space_read_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_CTRL0(cluster)); + val &= ~(1 << cpu); + bus_space_write_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_CTRL0(cluster), val); + + /* Release power clamp */ + for (i = 0; i <= CPU_PWR_CLAMP_STEPS; i++) + bus_space_write_4(fdtbus_bs_tag, prcm, + PRCM_CL_PWR_CLAMP(cluster, cpu), 0xff >> i); + while (bus_space_read_4(fdtbus_bs_tag, prcm, + PRCM_CL_PWR_CLAMP(cluster, cpu)) != 0) + ; + + /* Clear power-off gating */ + val = bus_space_read_4(fdtbus_bs_tag, prcm, PRCM_CL_PWROFF(cluster)); + val &= ~(1 << cpu); + bus_space_write_4(fdtbus_bs_tag, prcm, PRCM_CL_PWROFF(cluster), val); + + /* De-assert power-on reset */ + val = bus_space_read_4(fdtbus_bs_tag, cpuscfg, CPUS_CL_RST(cluster)); + val |= (1 << cpu); + bus_space_write_4(fdtbus_bs_tag, cpuscfg, CPUS_CL_RST(cluster), val); + + /* De-assert core reset */ + val = bus_space_read_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_RST(cluster)); + val |= (1 << cpu); + bus_space_write_4(fdtbus_bs_tag, cpuxcfg, CPUX_CL_RST(cluster), val); +} + +static void +aw_mc_mp_start_ap(bus_space_handle_t cpuscfg, bus_space_handle_t cpuxcfg, + bus_space_handle_t prcm) +{ + int cluster, cpu; + + KASSERT(mp_ncpus <= 4, ("multiple clusters not yet supported")); + + dcache_wbinv_poc_all(); + + bus_space_write_4(fdtbus_bs_tag, cpuscfg, CPUCFG_P_REG0, + pmap_kextract((vm_offset_t)mpentry)); + + cluster = 0; + for (cpu = 1; cpu < mp_ncpus; cpu++) + aw_mc_mp_start_cpu(cpuscfg, cpuxcfg, prcm, cluster, cpu); +} + +void +a83t_mp_start_ap(platform_t plat) +{ + bus_space_handle_t cpuscfg, cpuxcfg, prcm; + + if (bus_space_map(fdtbus_bs_tag, CPUCFG_BASE, CPUCFG_SIZE, + 0, &cpuscfg) != 0) + panic("Couldn't map the CPUCFG\n"); + if (bus_space_map(fdtbus_bs_tag, CPUXCFG_BASE, CPUXCFG_SIZE, + 0, &cpuxcfg) != 0) + panic("Couldn't map the CPUXCFG\n"); + if (bus_space_map(fdtbus_bs_tag, PRCM_BASE, PRCM_SIZE, 0, + &prcm) != 0) + panic("Couldn't map the PRCM\n"); + + aw_mc_mp_start_ap(cpuscfg, cpuxcfg, prcm); + armv7_sev(); + bus_space_unmap(fdtbus_bs_tag, cpuxcfg, CPUXCFG_SIZE); + bus_space_unmap(fdtbus_bs_tag, cpuscfg, CPUCFG_SIZE); + bus_space_unmap(fdtbus_bs_tag, prcm, PRCM_SIZE); +} diff --git a/sys/arm/allwinner/aw_mp.h b/sys/arm/allwinner/aw_mp.h index 402147a..591ecea 100644 --- a/sys/arm/allwinner/aw_mp.h +++ b/sys/arm/allwinner/aw_mp.h @@ -31,5 +31,6 @@ void aw_mp_setmaxid(platform_t plat); void a20_mp_start_ap(platform_t plat); void a31_mp_start_ap(platform_t plat); +void a83t_mp_start_ap(platform_t plat); #endif /* _AW_MP_H_ */ diff --git a/sys/arm/allwinner/aw_nmi.c b/sys/arm/allwinner/aw_nmi.c index 1cdd50e..2b23a4b 100644 --- a/sys/arm/allwinner/aw_nmi.c +++ b/sys/arm/allwinner/aw_nmi.c @@ -188,16 +188,18 @@ static int aw_nmi_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { + struct intr_map_data_fdt *daf; struct aw_nmi_softc *sc; int error; u_int irq; - sc = device_get_softc(dev); if (data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); - error = aw_nmi_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq, - NULL, NULL); + sc = device_get_softc(dev); + daf = (struct intr_map_data_fdt *)data; + + error = aw_nmi_map_fdt(dev, daf->ncells, daf->cells, &irq, NULL, NULL); if (error == 0) *isrcp = &sc->intr.isrc; @@ -208,6 +210,7 @@ static int aw_nmi_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { + struct intr_map_data_fdt *daf; struct aw_nmi_softc *sc; struct aw_nmi_intr *nmi_intr; int error, icfg; @@ -215,14 +218,15 @@ aw_nmi_setup_intr(device_t dev, struct intr_irqsrc *isrc, enum intr_trigger trig; enum intr_polarity pol; - sc = device_get_softc(dev); - nmi_intr = (struct aw_nmi_intr *)isrc; - /* Get config for interrupt. */ if (data == NULL || data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); - error = aw_nmi_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq, - &pol, &trig); + + sc = device_get_softc(dev); + nmi_intr = (struct aw_nmi_intr *)isrc; + daf = (struct intr_map_data_fdt *)data; + + error = aw_nmi_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol, &trig); if (error != 0) return (error); if (nmi_intr->irq != irq) diff --git a/sys/arm/allwinner/aw_usbphy.c b/sys/arm/allwinner/aw_usbphy.c index 25e8da0..31d2313 100644 --- a/sys/arm/allwinner/aw_usbphy.c +++ b/sys/arm/allwinner/aw_usbphy.c @@ -55,6 +55,7 @@ static struct ofw_compat_data compat_data[] = { { "allwinner,sun5i-a13-usb-phy", 1 }, { "allwinner,sun6i-a31-usb-phy", 1 }, { "allwinner,sun7i-a20-usb-phy", 1 }, + { "allwinner,sun8i-a83t-usb-phy", 1 }, { NULL, 0 } }; diff --git a/sys/arm/allwinner/clk/aw_ahbclk.c b/sys/arm/allwinner/clk/aw_ahbclk.c index 1d3b1a4..00a0afe 100644 --- a/sys/arm/allwinner/clk/aw_ahbclk.c +++ b/sys/arm/allwinner/clk/aw_ahbclk.c @@ -63,16 +63,35 @@ __FBSDID("$FreeBSD$"); #define A31_AHB1_CLK_SRC_SEL_MAX 3 #define A31_AHB1_CLK_SRC_SEL_SHIFT 12 +#define A83T_AHB1_CLK_SRC_SEL (0x3 << 12) +#define A83T_AHB1_CLK_SRC_SEL_ISPLL(x) ((x) & 0x2) +#define A83T_AHB1_CLK_SRC_SEL_MAX 3 +#define A83T_AHB1_CLK_SRC_SEL_SHIFT 12 +#define A83T_AHB1_PRE_DIV (0x3 << 6) +#define A83T_AHB1_PRE_DIV_SHIFT 6 +#define A83T_AHB1_CLK_DIV_RATIO (0x3 << 4) +#define A83T_AHB1_CLK_DIV_RATIO_SHIFT 4 + +#define H3_AHB2_CLK_CFG (0x3 << 0) +#define H3_AHB2_CLK_CFG_SHIFT 0 +#define H3_AHB2_CLK_CFG_AHB1 0 +#define H3_AHB2_CLK_CFG_PLL_PERIPH_DIV2 1 +#define H3_AHB2_CLK_CFG_MAX 1 + enum aw_ahbclk_type { AW_A10_AHB = 1, AW_A13_AHB, AW_A31_AHB1, + AW_A83T_AHB1, + AW_H3_AHB2, }; static struct ofw_compat_data compat_data[] = { { "allwinner,sun4i-a10-ahb-clk", AW_A10_AHB }, { "allwinner,sun5i-a13-ahb-clk", AW_A13_AHB }, { "allwinner,sun6i-a31-ahb1-clk", AW_A31_AHB1 }, + { "allwinner,sun8i-a83t-ahb1-clk", AW_A83T_AHB1 }, + { "allwinner,sun8i-h3-ahb2-clk", AW_H3_AHB2 }, { NULL, 0 } }; @@ -113,6 +132,19 @@ aw_ahbclk_init(struct clknode *clk, device_t dev) index = (val & A31_AHB1_CLK_SRC_SEL) >> A31_AHB1_CLK_SRC_SEL_SHIFT; break; + case AW_A83T_AHB1: + DEVICE_LOCK(sc); + AHBCLK_READ(sc, &val); + DEVICE_UNLOCK(sc); + index = (val & A83T_AHB1_CLK_SRC_SEL) >> + A83T_AHB1_CLK_SRC_SEL_SHIFT; + break; + case AW_H3_AHB2: + DEVICE_LOCK(sc); + AHBCLK_READ(sc, &val); + DEVICE_UNLOCK(sc); + index = (val & H3_AHB2_CLK_CFG) >> H3_AHB2_CLK_CFG_SHIFT; + break; default: return (ENXIO); } @@ -133,11 +165,10 @@ aw_ahbclk_recalc_freq(struct clknode *clk, uint64_t *freq) AHBCLK_READ(sc, &val); DEVICE_UNLOCK(sc); - div = 1 << ((val & A10_AHB_CLK_DIV_RATIO) >> - A10_AHB_CLK_DIV_RATIO_SHIFT); - switch (sc->type) { case AW_A31_AHB1: + div = 1 << ((val & A10_AHB_CLK_DIV_RATIO) >> + A10_AHB_CLK_DIV_RATIO_SHIFT); src_sel = (val & A31_AHB1_CLK_SRC_SEL) >> A31_AHB1_CLK_SRC_SEL_SHIFT; if (src_sel == A31_AHB1_CLK_SRC_SEL_PLL6) @@ -146,7 +177,28 @@ aw_ahbclk_recalc_freq(struct clknode *clk, uint64_t *freq) else pre_div = 1; break; + case AW_A83T_AHB1: + div = 1 << ((val & A83T_AHB1_CLK_DIV_RATIO) >> + A83T_AHB1_CLK_DIV_RATIO_SHIFT); + src_sel = (val & A83T_AHB1_CLK_SRC_SEL) >> + A83T_AHB1_CLK_SRC_SEL_SHIFT; + if (A83T_AHB1_CLK_SRC_SEL_ISPLL(src_sel)) + pre_div = ((val & A83T_AHB1_PRE_DIV) >> + A83T_AHB1_PRE_DIV_SHIFT) + 1; + else + pre_div = 1; + break; + case AW_H3_AHB2: + src_sel = (val & H3_AHB2_CLK_CFG) >> H3_AHB2_CLK_CFG_SHIFT; + if (src_sel == H3_AHB2_CLK_CFG_PLL_PERIPH_DIV2) + div = 2; + else + div = 1; + pre_div = 1; + break; default: + div = 1 << ((val & A10_AHB_CLK_DIV_RATIO) >> + A10_AHB_CLK_DIV_RATIO_SHIFT); pre_div = 1; break; } @@ -179,6 +231,26 @@ aw_ahbclk_set_mux(struct clknode *clk, int index) AHBCLK_WRITE(sc, val); DEVICE_UNLOCK(sc); break; + case AW_A83T_AHB1: + if (index < 0 || index > A83T_AHB1_CLK_SRC_SEL_MAX) + return (ERANGE); + DEVICE_LOCK(sc); + AHBCLK_READ(sc, &val); + val &= ~A83T_AHB1_CLK_SRC_SEL; + val |= (index << A83T_AHB1_CLK_SRC_SEL_SHIFT); + AHBCLK_WRITE(sc, val); + DEVICE_UNLOCK(sc); + break; + case AW_H3_AHB2: + if (index < 0 || index > H3_AHB2_CLK_CFG) + return (ERANGE); + DEVICE_LOCK(sc); + AHBCLK_READ(sc, &val); + val &= ~H3_AHB2_CLK_CFG; + val |= (index << H3_AHB2_CLK_CFG_SHIFT); + AHBCLK_WRITE(sc, val); + DEVICE_UNLOCK(sc); + break; default: return (ENXIO); } diff --git a/sys/arm/allwinner/clk/aw_apbclk.c b/sys/arm/allwinner/clk/aw_apbclk.c index a56387b..7620c45 100644 --- a/sys/arm/allwinner/clk/aw_apbclk.c +++ b/sys/arm/allwinner/clk/aw_apbclk.c @@ -49,24 +49,32 @@ __FBSDID("$FreeBSD$"); #include "clkdev_if.h" -#define APB0_CLK_RATIO (0x3 << 8) -#define APB0_CLK_RATIO_SHIFT 8 -#define APB1_CLK_SRC_SEL (0x3 << 24) -#define APB1_CLK_SRC_SEL_SHIFT 24 -#define APB1_CLK_SRC_SEL_MAX 0x3 -#define APB1_CLK_RAT_N (0x3 << 16) -#define APB1_CLK_RAT_N_SHIFT 16 -#define APB1_CLK_RAT_M (0x1f << 0) -#define APB1_CLK_RAT_M_SHIFT 0 +#define A10_APB0_CLK_RATIO (0x3 << 8) +#define A10_APB0_CLK_RATIO_SHIFT 8 +#define A10_APB1_CLK_SRC_SEL (0x3 << 24) +#define A10_APB1_CLK_SRC_SEL_SHIFT 24 +#define A10_APB1_CLK_SRC_SEL_MAX 0x3 +#define A10_APB1_CLK_RAT_N (0x3 << 16) +#define A10_APB1_CLK_RAT_N_SHIFT 16 +#define A10_APB1_CLK_RAT_M (0x1f << 0) +#define A10_APB1_CLK_RAT_M_SHIFT 0 +#define A23_APB0_CLK_RATIO (0x3 << 0) +#define A23_APB0_CLK_RATIO_SHIFT 0 +#define A83T_APB1_CLK_RATIO (0x3 << 8) +#define A83T_APB1_CLK_RATIO_SHIFT 8 enum aw_apbclk_type { AW_A10_APB0 = 1, AW_A10_APB1, + AW_A23_APB0, + AW_A83T_APB1, }; static struct ofw_compat_data compat_data[] = { { "allwinner,sun4i-a10-apb0-clk", AW_A10_APB0 }, { "allwinner,sun4i-a10-apb1-clk", AW_A10_APB1 }, + { "allwinner,sun8i-a23-apb0-clk", AW_A23_APB0 }, + { "allwinner,sun8i-a83t-apb1-clk", AW_A83T_APB1 }, { NULL, 0 } }; @@ -91,13 +99,16 @@ aw_apbclk_init(struct clknode *clk, device_t dev) switch (sc->type) { case AW_A10_APB0: + case AW_A23_APB0: + case AW_A83T_APB1: index = 0; break; case AW_A10_APB1: DEVICE_LOCK(sc); APBCLK_READ(sc, &val); DEVICE_UNLOCK(sc); - index = (val & APB1_CLK_SRC_SEL) >> APB1_CLK_SRC_SEL_SHIFT; + index = (val & A10_APB1_CLK_SRC_SEL) >> + A10_APB1_CLK_SRC_SEL_SHIFT; break; default: return (ENXIO); @@ -121,16 +132,29 @@ aw_apbclk_recalc_freq(struct clknode *clk, uint64_t *freq) switch (sc->type) { case AW_A10_APB0: - div = 1 << ((val & APB0_CLK_RATIO) >> APB0_CLK_RATIO_SHIFT); + div = 1 << ((val & A10_APB0_CLK_RATIO) >> + A10_APB0_CLK_RATIO_SHIFT); if (div == 1) div = 2; *freq = *freq / div; break; case AW_A10_APB1: - n = 1 << ((val & APB1_CLK_RAT_N) >> APB1_CLK_RAT_N_SHIFT); - m = ((val & APB1_CLK_RAT_N) >> APB1_CLK_RAT_M_SHIFT) + 1; + n = 1 << ((val & A10_APB1_CLK_RAT_N) >> + A10_APB1_CLK_RAT_N_SHIFT); + m = ((val & A10_APB1_CLK_RAT_N) >> + A10_APB1_CLK_RAT_M_SHIFT) + 1; *freq = *freq / n / m; break; + case AW_A23_APB0: + div = 1 << ((val & A23_APB0_CLK_RATIO) >> + A23_APB0_CLK_RATIO_SHIFT); + *freq = *freq / div; + break; + case AW_A83T_APB1: + div = ((val & A83T_APB1_CLK_RATIO) >> + A83T_APB1_CLK_RATIO_SHIFT) + 1; + *freq = *freq / div; + break; default: return (ENXIO); } @@ -149,13 +173,13 @@ aw_apbclk_set_mux(struct clknode *clk, int index) if (sc->type != AW_A10_APB1) return (ENXIO); - if (index < 0 || index > APB1_CLK_SRC_SEL_MAX) + if (index < 0 || index > A10_APB1_CLK_SRC_SEL_MAX) return (ERANGE); DEVICE_LOCK(sc); APBCLK_READ(sc, &val); - val &= ~APB1_CLK_SRC_SEL; - val |= (index << APB1_CLK_SRC_SEL_SHIFT); + val &= ~A10_APB1_CLK_SRC_SEL; + val |= (index << A10_APB1_CLK_SRC_SEL_SHIFT); APBCLK_WRITE(sc, val); DEVICE_UNLOCK(sc); diff --git a/sys/arm/allwinner/clk/aw_cpusclk.c b/sys/arm/allwinner/clk/aw_cpusclk.c new file mode 100644 index 0000000..6d18284 --- /dev/null +++ b/sys/arm/allwinner/clk/aw_cpusclk.c @@ -0,0 +1,320 @@ +/*- + * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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 + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Allwinner CPUS clock + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/rman.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <machine/bus.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> +#include <dev/ofw/ofw_subr.h> + +#include <dev/extres/clk/clk.h> + +#include "clkdev_if.h" + +#define A80_CPUS_CLK_SRC_SEL (0x3 << 16) +#define A80_CPUS_CLK_SRC_SEL_SHIFT 16 +#define A80_CPUS_CLK_SRC_SEL_X32KI 0 +#define A80_CPUS_CLK_SRC_SEL_OSC24M 1 +#define A80_CPUS_CLK_SRC_SEL_PLL_PERIPH 2 +#define A80_CPUS_CLK_SRC_SEL_PLL_AUDIO 3 +#define A80_CPUS_POST_DIV (0x1f << 8) +#define A80_CPUS_POST_DIV_SHIFT 8 +#define A80_CPUS_CLK_RATIO (0x3 << 4) +#define A80_CPUS_CLK_RATIO_SHIFT 4 + +#define A83T_CPUS_CLK_SRC_SEL (0x3 << 16) +#define A83T_CPUS_CLK_SRC_SEL_SHIFT 16 +#define A83T_CPUS_CLK_SRC_SEL_X32KI 0 +#define A83T_CPUS_CLK_SRC_SEL_OSC24M 1 +#define A83T_CPUS_CLK_SRC_SEL_PLL_PERIPH 2 +#define A83T_CPUS_CLK_SRC_SEL_INTERNAL_OSC 3 +#define A83T_CPUS_POST_DIV (0x1f << 8) +#define A83T_CPUS_POST_DIV_SHIFT 8 +#define A83T_CPUS_CLK_RATIO (0x3 << 4) +#define A83T_CPUS_CLK_RATIO_SHIFT 4 + +enum aw_cpusclk_type { + AW_A80_CPUS = 1, + AW_A83T_CPUS, +}; + +static struct ofw_compat_data compat_data[] = { + { "allwinner,sun9i-a80-cpus-clk", AW_A80_CPUS }, + { "allwinner,sun8i-a83t-cpus-clk", AW_A83T_CPUS }, + { NULL, 0 } +}; + +struct aw_cpusclk_sc { + device_t clkdev; + bus_addr_t reg; + enum aw_cpusclk_type type; +}; + +#define CPUSCLK_READ(sc, val) CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val)) +#define CPUSCLK_WRITE(sc, val) CLKDEV_WRITE_4((sc)->clkdev, (sc)->reg, (val)) +#define DEVICE_LOCK(sc) CLKDEV_DEVICE_LOCK((sc)->clkdev) +#define DEVICE_UNLOCK(sc) CLKDEV_DEVICE_UNLOCK((sc)->clkdev) + +static int +aw_cpusclk_init(struct clknode *clk, device_t dev) +{ + struct aw_cpusclk_sc *sc; + uint32_t val, mask, shift, index; + + sc = clknode_get_softc(clk); + + switch (sc->type) { + case AW_A80_CPUS: + mask = A80_CPUS_CLK_SRC_SEL; + shift = A80_CPUS_CLK_SRC_SEL_SHIFT; + break; + case AW_A83T_CPUS: + mask = A83T_CPUS_CLK_SRC_SEL; + shift = A83T_CPUS_CLK_SRC_SEL_SHIFT; + break; + default: + return (ENXIO); + } + + DEVICE_LOCK(sc); + CPUSCLK_READ(sc, &val); + DEVICE_UNLOCK(sc); + index = (val & mask) >> shift; + + clknode_init_parent_idx(clk, index); + return (0); +} + +static int +aw_cpusclk_recalc_freq(struct clknode *clk, uint64_t *freq) +{ + struct aw_cpusclk_sc *sc; + uint32_t val, src_sel, post_div, clk_ratio; + + sc = clknode_get_softc(clk); + + DEVICE_LOCK(sc); + CPUSCLK_READ(sc, &val); + DEVICE_UNLOCK(sc); + + switch (sc->type) { + case AW_A80_CPUS: + src_sel = (val & A80_CPUS_CLK_SRC_SEL) >> + A80_CPUS_CLK_SRC_SEL_SHIFT; + post_div = ((val & A80_CPUS_POST_DIV) >> + A80_CPUS_POST_DIV_SHIFT) + 1; + clk_ratio = ((val & A80_CPUS_CLK_RATIO) >> + A80_CPUS_CLK_RATIO_SHIFT) + 1; + if (src_sel == A80_CPUS_CLK_SRC_SEL_PLL_PERIPH) + *freq = *freq / post_div / clk_ratio; + else + *freq = *freq / clk_ratio; + break; + case AW_A83T_CPUS: + src_sel = (val & A83T_CPUS_CLK_SRC_SEL) >> + A83T_CPUS_CLK_SRC_SEL_SHIFT; + post_div = ((val & A83T_CPUS_POST_DIV) >> + A83T_CPUS_POST_DIV_SHIFT) + 1; + clk_ratio = 1 << ((val & A83T_CPUS_CLK_RATIO) >> + A83T_CPUS_CLK_RATIO_SHIFT); + if (src_sel == A83T_CPUS_CLK_SRC_SEL_PLL_PERIPH) + *freq = *freq / post_div / clk_ratio; + else + *freq = *freq / clk_ratio; + break; + default: + return (EINVAL); + } + + return (0); +} + +static int +aw_cpusclk_set_mux(struct clknode *clk, int index) +{ + struct aw_cpusclk_sc *sc; + uint32_t mask, shift, val; + + sc = clknode_get_softc(clk); + + switch (sc->type) { + case AW_A80_CPUS: + mask = A80_CPUS_CLK_SRC_SEL; + shift = A80_CPUS_CLK_SRC_SEL_SHIFT; + break; + case AW_A83T_CPUS: + mask = A83T_CPUS_CLK_SRC_SEL; + shift = A83T_CPUS_CLK_SRC_SEL_SHIFT; + break; + default: + return (ENXIO); + } + + DEVICE_LOCK(sc); + CPUSCLK_READ(sc, &val); + val &= ~mask; + val |= (index << shift); + CPUSCLK_WRITE(sc, val); + DEVICE_UNLOCK(sc); + + return (0); +} + +static clknode_method_t aw_cpusclk_clknode_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, aw_cpusclk_init), + CLKNODEMETHOD(clknode_recalc_freq, aw_cpusclk_recalc_freq), + CLKNODEMETHOD(clknode_set_mux, aw_cpusclk_set_mux), + CLKNODEMETHOD_END +}; +DEFINE_CLASS_1(aw_cpusclk_clknode, aw_cpusclk_clknode_class, + aw_cpusclk_clknode_methods, sizeof(struct aw_cpusclk_sc), clknode_class); + +static int +aw_cpusclk_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "Allwinner CPUS Clock"); + return (BUS_PROBE_DEFAULT); +} + +static int +aw_cpusclk_attach(device_t dev) +{ + struct clknode_init_def def; + struct aw_cpusclk_sc *sc; + struct clkdom *clkdom; + struct clknode *clk; + clk_t clk_parent; + bus_addr_t paddr; + bus_size_t psize; + phandle_t node; + int error, ncells, i; + + node = ofw_bus_get_node(dev); + + if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) { + device_printf(dev, "cannot parse 'reg' property\n"); + return (ENXIO); + } + + error = ofw_bus_parse_xref_list_get_length(node, "clocks", + "#clock-cells", &ncells); + if (error != 0) { + device_printf(dev, "cannot get clock count\n"); + return (error); + } + + clkdom = clkdom_create(dev); + + memset(&def, 0, sizeof(def)); + def.id = 1; + def.parent_names = malloc(sizeof(char *) * ncells, M_OFWPROP, + M_WAITOK); + for (i = 0; i < ncells; i++) { + error = clk_get_by_ofw_index(dev, i, &clk_parent); + if (error != 0) { + device_printf(dev, "cannot get clock %d\n", i); + goto fail; + } + def.parent_names[i] = clk_get_name(clk_parent); + clk_release(clk_parent); + } + def.parent_cnt = ncells; + + error = clk_parse_ofw_clk_name(dev, node, &def.name); + if (error != 0) { + device_printf(dev, "cannot parse clock name\n"); + error = ENXIO; + goto fail; + } + + clk = clknode_create(clkdom, &aw_cpusclk_clknode_class, &def); + if (clk == NULL) { + device_printf(dev, "cannot create clknode\n"); + error = ENXIO; + goto fail; + } + sc = clknode_get_softc(clk); + sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; + sc->reg = paddr; + sc->clkdev = device_get_parent(dev); + + clknode_register(clkdom, clk); + + if (clkdom_finit(clkdom) != 0) { + device_printf(dev, "cannot finalize clkdom initialization\n"); + error = ENXIO; + goto fail; + } + + if (bootverbose) + clkdom_dump(clkdom); + + return (0); + +fail: + return (error); +} + +static device_method_t aw_cpusclk_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, aw_cpusclk_probe), + DEVMETHOD(device_attach, aw_cpusclk_attach), + + DEVMETHOD_END +}; + +static driver_t aw_cpusclk_driver = { + "aw_cpusclk", + aw_cpusclk_methods, + 0 +}; + +static devclass_t aw_cpusclk_devclass; + +EARLY_DRIVER_MODULE(aw_cpusclk, simplebus, aw_cpusclk_driver, + aw_cpusclk_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); diff --git a/sys/arm/allwinner/clk/aw_gate.c b/sys/arm/allwinner/clk/aw_gate.c index d43d021..6634c57 100644 --- a/sys/arm/allwinner/clk/aw_gate.c +++ b/sys/arm/allwinner/clk/aw_gate.c @@ -76,6 +76,14 @@ static struct ofw_compat_data compat_data[] = { { "allwinner,sun6i-a31-apb2-gates-clk", (uintptr_t)"Allwinner APB2 Clock Gates" }, + { "allwinner,sun8i-a83t-bus-gates-clk", + (uintptr_t)"Allwinner Bus Clock Gates" }, + { "allwinner,sun8i-a83t-apb0-gates-clk", + (uintptr_t)"Allwinner APB0 Clock Gates" }, + + { "allwinner,sun9i-a80-apbs-gates-clk", + (uintptr_t)"Allwinner APBS Clock Gates" }, + { NULL, 0 } }; diff --git a/sys/arm/allwinner/clk/aw_gmacclk.c b/sys/arm/allwinner/clk/aw_gmacclk.c index 5e2f618..72495fd 100644 --- a/sys/arm/allwinner/clk/aw_gmacclk.c +++ b/sys/arm/allwinner/clk/aw_gmacclk.c @@ -60,18 +60,41 @@ __FBSDID("$FreeBSD$"); #define GMAC_CLK_SRC_EXT_RGMII 1 #define GMAC_CLK_SRC_RGMII 2 +#define EMAC_TXC_DIV_CFG (1 << 15) +#define EMAC_TXC_DIV_CFG_SHIFT 15 +#define EMAC_TXC_DIV_CFG_125MHZ 0 +#define EMAC_TXC_DIV_CFG_25MHZ 1 +#define EMAC_PHY_SELECT (1 << 16) +#define EMAC_PHY_SELECT_SHIFT 16 +#define EMAC_PHY_SELECT_INT 0 +#define EMAC_PHY_SELECT_EXT 1 +#define EMAC_ETXDC (0x7 << 10) +#define EMAC_ETXDC_SHIFT 10 +#define EMAC_ERXDC (0x1f << 5) +#define EMAC_ERXDC_SHIFT 5 + #define CLK_IDX_MII 0 #define CLK_IDX_RGMII 1 #define CLK_IDX_COUNT 2 +enum aw_gmacclk_type { + GMACCLK_A20 = 1, + GMACCLK_A83T, +}; + static struct ofw_compat_data compat_data[] = { - { "allwinner,sun7i-a20-gmac-clk", 1 }, + { "allwinner,sun7i-a20-gmac-clk", GMACCLK_A20 }, + { "allwinner,sun8i-a83t-emac-clk", GMACCLK_A83T }, { NULL, 0 } }; struct aw_gmacclk_sc { device_t clkdev; bus_addr_t reg; + enum aw_gmacclk_type type; + + int rx_delay; + int tx_delay; }; #define GMACCLK_READ(sc, val) CLKDEV_READ_4((sc)->clkdev, (sc)->reg, (val)) @@ -110,7 +133,7 @@ static int aw_gmacclk_set_mux(struct clknode *clk, int index) { struct aw_gmacclk_sc *sc; - uint32_t val, clk_src, pit; + uint32_t val, clk_src, pit, txc_div; int error; sc = clknode_get_softc(clk); @@ -120,10 +143,12 @@ aw_gmacclk_set_mux(struct clknode *clk, int index) case CLK_IDX_MII: clk_src = GMAC_CLK_SRC_MII; pit = GMAC_CLK_PIT_MII; + txc_div = EMAC_TXC_DIV_CFG_25MHZ; break; case CLK_IDX_RGMII: clk_src = GMAC_CLK_SRC_RGMII; pit = GMAC_CLK_PIT_RGMII; + txc_div = EMAC_TXC_DIV_CFG_125MHZ; break; default: return (ENXIO); @@ -134,6 +159,20 @@ aw_gmacclk_set_mux(struct clknode *clk, int index) val &= ~(GMAC_CLK_SRC | GMAC_CLK_PIT); val |= (clk_src << GMAC_CLK_SRC_SHIFT); val |= (pit << GMAC_CLK_PIT_SHIFT); + if (sc->type == GMACCLK_A83T) { + val &= ~EMAC_TXC_DIV_CFG; + val |= (txc_div << EMAC_TXC_DIV_CFG_SHIFT); + val &= ~EMAC_PHY_SELECT; + val |= (EMAC_PHY_SELECT_EXT << EMAC_PHY_SELECT_SHIFT); + if (sc->tx_delay >= 0) { + val &= ~EMAC_ETXDC; + val |= (sc->tx_delay << EMAC_ETXDC_SHIFT); + } + if (sc->rx_delay >= 0) { + val &= ~EMAC_ERXDC; + val |= (sc->rx_delay << EMAC_ERXDC_SHIFT); + } + } GMACCLK_WRITE(sc, val); DEVICE_UNLOCK(sc); @@ -158,7 +197,7 @@ aw_gmacclk_probe(device_t dev) if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); - device_set_desc(dev, "Allwinner Module Clock"); + device_set_desc(dev, "Allwinner GMAC Clock"); return (BUS_PROBE_DEFAULT); } @@ -221,6 +260,10 @@ aw_gmacclk_attach(device_t dev) sc = clknode_get_softc(clk); sc->reg = paddr; sc->clkdev = device_get_parent(dev); + sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; + sc->tx_delay = sc->rx_delay = -1; + OF_getencprop(node, "tx-delay", &sc->tx_delay, sizeof(sc->tx_delay)); + OF_getencprop(node, "rx-delay", &sc->rx_delay, sizeof(sc->rx_delay)); clknode_register(clkdom, clk); diff --git a/sys/arm/allwinner/clk/aw_pll.c b/sys/arm/allwinner/clk/aw_pll.c index 2e67646..b7c2a7e 100644 --- a/sys/arm/allwinner/clk/aw_pll.c +++ b/sys/arm/allwinner/clk/aw_pll.c @@ -124,6 +124,12 @@ __FBSDID("$FreeBSD$"); #define A31_PLL6_DEFAULT_K 0x1 #define A31_PLL6_TIMEOUT 10 +#define A80_PLL4_CLK_OUT_EN (1 << 20) +#define A80_PLL4_PLL_DIV2 (1 << 18) +#define A80_PLL4_PLL_DIV1 (1 << 16) +#define A80_PLL4_FACTOR_N (0xff << 8) +#define A80_PLL4_FACTOR_N_SHIFT 8 + #define CLKID_A10_PLL3_1X 0 #define CLKID_A10_PLL3_2X 1 @@ -146,6 +152,7 @@ enum aw_pll_type { AWPLL_A10_PLL6, AWPLL_A31_PLL1, AWPLL_A31_PLL6, + AWPLL_A80_PLL4, }; struct aw_pll_sc { @@ -524,6 +531,24 @@ a31_pll6_recalc(struct aw_pll_sc *sc, uint64_t *freq) return (0); } +static int +a80_pll4_recalc(struct aw_pll_sc *sc, uint64_t *freq) +{ + uint32_t val, n, div1, div2; + + DEVICE_LOCK(sc); + PLL_READ(sc, &val); + DEVICE_UNLOCK(sc); + + n = (val & A80_PLL4_FACTOR_N) >> A80_PLL4_FACTOR_N_SHIFT; + div1 = (val & A80_PLL4_PLL_DIV1) == 0 ? 1 : 2; + div2 = (val & A80_PLL4_PLL_DIV2) == 0 ? 1 : 2; + + *freq = (*freq * n) / div1 / div2; + + return (0); +} + #define PLL(_type, _recalc, _set_freq, _init) \ [(_type)] = { \ .recalc = (_recalc), \ @@ -539,6 +564,7 @@ static struct aw_pll_funcs aw_pll_func[] = { PLL(AWPLL_A10_PLL6, a10_pll6_recalc, a10_pll6_set_freq, a10_pll6_init), PLL(AWPLL_A31_PLL1, a31_pll1_recalc, NULL, NULL), PLL(AWPLL_A31_PLL6, a31_pll6_recalc, NULL, a31_pll6_init), + PLL(AWPLL_A80_PLL4, a80_pll4_recalc, NULL, NULL), }; static struct ofw_compat_data compat_data[] = { @@ -549,6 +575,7 @@ static struct ofw_compat_data compat_data[] = { { "allwinner,sun4i-a10-pll6-clk", AWPLL_A10_PLL6 }, { "allwinner,sun6i-a31-pll1-clk", AWPLL_A31_PLL1 }, { "allwinner,sun6i-a31-pll6-clk", AWPLL_A31_PLL6 }, + { "allwinner,sun9i-a80-pll4-clk", AWPLL_A80_PLL4 }, { NULL, 0 } }; diff --git a/sys/arm/allwinner/clk/aw_usbclk.c b/sys/arm/allwinner/clk/aw_usbclk.c index bac9991..cd935c4 100644 --- a/sys/arm/allwinner/clk/aw_usbclk.c +++ b/sys/arm/allwinner/clk/aw_usbclk.c @@ -62,11 +62,13 @@ __FBSDID("$FreeBSD$"); enum aw_usbclk_type { AW_A10_USBCLK = 1, AW_A31_USBCLK, + AW_A83T_USBCLK, }; static struct ofw_compat_data compat_data[] = { { "allwinner,sun4i-a10-usb-clk", AW_A10_USBCLK }, { "allwinner,sun6i-a31-usb-clk", AW_A31_USBCLK }, + { "allwinner,sun8i-a83t-usb-clk", AW_A83T_USBCLK }, { NULL, 0 } }; @@ -162,10 +164,11 @@ aw_usbclk_attach(device_t dev) struct aw_usbclk_softc *sc; struct clkdom *clkdom; const char **names; + const char *pname; int index, nout, error; enum aw_usbclk_type type; uint32_t *indices; - clk_t clk_parent; + clk_t clk_parent, clk_parent_pll; bus_size_t psize; phandle_t node; @@ -196,11 +199,21 @@ aw_usbclk_attach(device_t dev) device_printf(dev, "cannot parse clock parent\n"); return (ENXIO); } + if (type == AW_A83T_USBCLK) { + error = clk_get_by_ofw_index(dev, 1, &clk_parent_pll); + if (error != 0) { + device_printf(dev, "cannot parse pll clock parent\n"); + return (ENXIO); + } + } for (index = 0; index < nout; index++) { - error = aw_usbclk_create(dev, sc->reg, clkdom, - clk_get_name(clk_parent), names[index], - indices != NULL ? indices[index] : index); + if (strcmp(names[index], "usb_hsic_pll") == 0) + pname = clk_get_name(clk_parent_pll); + else + pname = clk_get_name(clk_parent); + error = aw_usbclk_create(dev, sc->reg, clkdom, pname, + names[index], indices != NULL ? indices[index] : index); if (error) goto fail; } diff --git a/sys/arm/allwinner/files.allwinner b/sys/arm/allwinner/files.allwinner index d02a868..a138989 100644 --- a/sys/arm/allwinner/files.allwinner +++ b/sys/arm/allwinner/files.allwinner @@ -18,6 +18,7 @@ arm/allwinner/a20/a20_cpu_cfg.c standard arm/allwinner/allwinner_machdep.c standard arm/allwinner/aw_mp.c optional smp arm/allwinner/axp209.c optional axp209 +arm/allwinner/if_awg.c optional awg arm/allwinner/if_emac.c optional emac arm/allwinner/sunxi_dma_if.m standard dev/iicbus/twsi/a10_twsi.c optional twsi @@ -35,6 +36,7 @@ arm/allwinner/clk/aw_apbclk.c standard arm/allwinner/clk/aw_axiclk.c standard arm/allwinner/clk/aw_codecclk.c standard arm/allwinner/clk/aw_cpuclk.c standard +arm/allwinner/clk/aw_cpusclk.c standard arm/allwinner/clk/aw_debeclk.c standard arm/allwinner/clk/aw_gate.c standard arm/allwinner/clk/aw_gmacclk.c standard diff --git a/sys/arm/allwinner/if_awg.c b/sys/arm/allwinner/if_awg.c new file mode 100644 index 0000000..87606c3 --- /dev/null +++ b/sys/arm/allwinner/if_awg.c @@ -0,0 +1,1418 @@ +/*- + * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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 + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Allwinner Gigabit Ethernet MAC (EMAC) controller + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/rman.h> +#include <sys/kernel.h> +#include <sys/endian.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/module.h> +#include <sys/taskqueue.h> + +#include <net/bpf.h> +#include <net/if.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> +#include <net/if_var.h> + +#include <machine/bus.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <arm/allwinner/if_awgreg.h> +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include <dev/extres/clk/clk.h> +#include <dev/extres/hwreset/hwreset.h> +#include <dev/extres/regulator/regulator.h> + +#include "miibus_if.h" + +#define RD4(sc, reg) bus_read_4((sc)->res[0], (reg)) +#define WR4(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val)) + +#define AWG_LOCK(sc) mtx_lock(&(sc)->mtx) +#define AWG_UNLOCK(sc) mtx_unlock(&(sc)->mtx); +#define AWG_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED) +#define AWG_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED) + +#define DESC_ALIGN 4 +#define TX_DESC_COUNT 256 +#define TX_DESC_SIZE (sizeof(struct emac_desc) * TX_DESC_COUNT) +#define RX_DESC_COUNT 256 +#define RX_DESC_SIZE (sizeof(struct emac_desc) * RX_DESC_COUNT) + +#define DESC_OFF(n) ((n) * sizeof(struct emac_desc)) +#define TX_NEXT(n) (((n) + 1) & (TX_DESC_COUNT - 1)) +#define TX_SKIP(n, o) (((n) + (o)) & (TX_DESC_COUNT - 1)) +#define RX_NEXT(n) (((n) + 1) & (RX_DESC_COUNT - 1)) + +#define TX_MAX_SEGS 10 + +#define SOFT_RST_RETRY 1000 +#define MII_BUSY_RETRY 1000 +#define MDIO_FREQ 2500000 + +#define BURST_LEN_DEFAULT 8 +#define RX_TX_PRI_DEFAULT 0 +#define PAUSE_TIME_DEFAULT 0x400 +#define TX_INTERVAL_DEFAULT 64 + +/* Burst length of RX and TX DMA transfers */ +static int awg_burst_len = BURST_LEN_DEFAULT; +TUNABLE_INT("hw.awg.burst_len", &awg_burst_len); + +/* RX / TX DMA priority. If 1, RX DMA has priority over TX DMA. */ +static int awg_rx_tx_pri = RX_TX_PRI_DEFAULT; +TUNABLE_INT("hw.awg.rx_tx_pri", &awg_rx_tx_pri); + +/* Pause time field in the transmitted control frame */ +static int awg_pause_time = PAUSE_TIME_DEFAULT; +TUNABLE_INT("hw.awg.pause_time", &awg_pause_time); + +/* Request a TX interrupt every <n> descriptors */ +static int awg_tx_interval = TX_INTERVAL_DEFAULT; +TUNABLE_INT("hw.awg.tx_interval", &awg_tx_interval); + +static struct ofw_compat_data compat_data[] = { + { "allwinner,sun8i-a83t-emac", 1 }, + { NULL, 0 } +}; + +struct awg_bufmap { + bus_dmamap_t map; + struct mbuf *mbuf; +}; + +struct awg_txring { + bus_dma_tag_t desc_tag; + bus_dmamap_t desc_map; + struct emac_desc *desc_ring; + bus_addr_t desc_ring_paddr; + bus_dma_tag_t buf_tag; + struct awg_bufmap buf_map[TX_DESC_COUNT]; + u_int cur, next, queued; +}; + +struct awg_rxring { + bus_dma_tag_t desc_tag; + bus_dmamap_t desc_map; + struct emac_desc *desc_ring; + bus_addr_t desc_ring_paddr; + bus_dma_tag_t buf_tag; + struct awg_bufmap buf_map[RX_DESC_COUNT]; + u_int cur; +}; + +struct awg_softc { + struct resource *res[2]; + struct mtx mtx; + if_t ifp; + device_t miibus; + struct callout stat_ch; + struct task link_task; + void *ih; + u_int mdc_div_ratio_m; + int link; + int if_flags; + + struct awg_txring tx; + struct awg_rxring rx; +}; + +static struct resource_spec awg_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static int +awg_miibus_readreg(device_t dev, int phy, int reg) +{ + struct awg_softc *sc; + int retry, val; + + sc = device_get_softc(dev); + val = 0; + + WR4(sc, EMAC_MII_CMD, + (sc->mdc_div_ratio_m << MDC_DIV_RATIO_M_SHIFT) | + (phy << PHY_ADDR_SHIFT) | + (reg << PHY_REG_ADDR_SHIFT) | + MII_BUSY); + for (retry = MII_BUSY_RETRY; retry > 0; retry--) { + if ((RD4(sc, EMAC_MII_CMD) & MII_BUSY) == 0) { + val = RD4(sc, EMAC_MII_DATA); + break; + } + DELAY(10); + } + + if (retry == 0) + device_printf(dev, "phy read timeout, phy=%d reg=%d\n", + phy, reg); + + return (val); +} + +static int +awg_miibus_writereg(device_t dev, int phy, int reg, int val) +{ + struct awg_softc *sc; + int retry; + + sc = device_get_softc(dev); + + WR4(sc, EMAC_MII_DATA, val); + WR4(sc, EMAC_MII_CMD, + (sc->mdc_div_ratio_m << MDC_DIV_RATIO_M_SHIFT) | + (phy << PHY_ADDR_SHIFT) | + (reg << PHY_REG_ADDR_SHIFT) | + MII_WR | MII_BUSY); + for (retry = MII_BUSY_RETRY; retry > 0; retry--) { + if ((RD4(sc, EMAC_MII_CMD) & MII_BUSY) == 0) + break; + DELAY(10); + } + + if (retry == 0) + device_printf(dev, "phy write timeout, phy=%d reg=%d\n", + phy, reg); + + return (0); +} + +static void +awg_update_link_locked(struct awg_softc *sc) +{ + struct mii_data *mii; + uint32_t val; + + AWG_ASSERT_LOCKED(sc); + + if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) == 0) + return; + mii = device_get_softc(sc->miibus); + + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_1000_T: + case IFM_1000_SX: + case IFM_100_TX: + case IFM_10_T: + sc->link = 1; + break; + default: + sc->link = 0; + break; + } + } else + sc->link = 0; + + if (sc->link == 0) + return; + + val = RD4(sc, EMAC_BASIC_CTL_0); + val &= ~(BASIC_CTL_SPEED | BASIC_CTL_DUPLEX); + + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || + IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) + val |= BASIC_CTL_SPEED_1000 << BASIC_CTL_SPEED_SHIFT; + else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) + val |= BASIC_CTL_SPEED_100 << BASIC_CTL_SPEED_SHIFT; + else + val |= BASIC_CTL_SPEED_10 << BASIC_CTL_SPEED_SHIFT; + + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) + val |= BASIC_CTL_DUPLEX; + + WR4(sc, EMAC_BASIC_CTL_0, val); + + val = RD4(sc, EMAC_RX_CTL_0); + val &= ~RX_FLOW_CTL_EN; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) + val |= RX_FLOW_CTL_EN; + WR4(sc, EMAC_RX_CTL_0, val); + + val = RD4(sc, EMAC_TX_FLOW_CTL); + val &= ~(PAUSE_TIME|TX_FLOW_CTL_EN); + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) + val |= TX_FLOW_CTL_EN; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) + val |= awg_pause_time << PAUSE_TIME_SHIFT; + WR4(sc, EMAC_TX_FLOW_CTL, val); +} + +static void +awg_link_task(void *arg, int pending) +{ + struct awg_softc *sc; + + sc = arg; + + AWG_LOCK(sc); + awg_update_link_locked(sc); + AWG_UNLOCK(sc); +} + +static void +awg_miibus_statchg(device_t dev) +{ + struct awg_softc *sc; + + sc = device_get_softc(dev); + + taskqueue_enqueue(taskqueue_swi, &sc->link_task); +} + +static void +awg_media_status(if_t ifp, struct ifmediareq *ifmr) +{ + struct awg_softc *sc; + struct mii_data *mii; + + sc = if_getsoftc(ifp); + mii = device_get_softc(sc->miibus); + + AWG_LOCK(sc); + mii_pollstat(mii); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; + AWG_UNLOCK(sc); +} + +static int +awg_media_change(if_t ifp) +{ + struct awg_softc *sc; + struct mii_data *mii; + int error; + + sc = if_getsoftc(ifp); + mii = device_get_softc(sc->miibus); + + AWG_LOCK(sc); + error = mii_mediachg(mii); + AWG_UNLOCK(sc); + + return (error); +} + +static void +awg_setup_txdesc(struct awg_softc *sc, int index, int flags, bus_addr_t paddr, + u_int len) +{ + uint32_t status, size; + + if (paddr == 0 || len == 0) { + status = 0; + size = 0; + --sc->tx.queued; + } else { + status = TX_DESC_CTL; + size = flags | len; + if ((index & (awg_tx_interval - 1)) == 0) + size |= htole32(TX_INT_CTL); + ++sc->tx.queued; + } + + sc->tx.desc_ring[index].addr = htole32((uint32_t)paddr); + sc->tx.desc_ring[index].size = htole32(size); + sc->tx.desc_ring[index].status = htole32(status); +} + +static int +awg_setup_txbuf(struct awg_softc *sc, int index, struct mbuf **mp) +{ + bus_dma_segment_t segs[TX_MAX_SEGS]; + int error, nsegs, cur, i, flags; + u_int csum_flags; + struct mbuf *m; + + m = *mp; + error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag, + sc->tx.buf_map[index].map, m, segs, &nsegs, BUS_DMA_NOWAIT); + if (error == EFBIG) { + m = m_collapse(m, M_NOWAIT, TX_MAX_SEGS); + if (m == NULL) + return (0); + *mp = m; + error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag, + sc->tx.buf_map[index].map, m, segs, &nsegs, BUS_DMA_NOWAIT); + } + if (error != 0) + return (0); + + bus_dmamap_sync(sc->tx.buf_tag, sc->tx.buf_map[index].map, + BUS_DMASYNC_PREWRITE); + + flags = TX_FIR_DESC; + if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) { + if ((m->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_UDP)) != 0) + csum_flags = TX_CHECKSUM_CTL_FULL; + else + csum_flags = TX_CHECKSUM_CTL_IP; + flags |= (csum_flags << TX_CHECKSUM_CTL_SHIFT); + } + + for (cur = index, i = 0; i < nsegs; i++) { + sc->tx.buf_map[cur].mbuf = (i == 0 ? m : NULL); + if (i == nsegs - 1) + flags |= TX_LAST_DESC; + awg_setup_txdesc(sc, cur, flags, segs[i].ds_addr, + segs[i].ds_len); + flags &= ~TX_FIR_DESC; + cur = TX_NEXT(cur); + } + + return (nsegs); +} + +static void +awg_setup_rxdesc(struct awg_softc *sc, int index, bus_addr_t paddr) +{ + uint32_t status, size; + + status = RX_DESC_CTL; + size = MCLBYTES - 1; + + sc->rx.desc_ring[index].addr = htole32((uint32_t)paddr); + sc->rx.desc_ring[index].size = htole32(size); + sc->rx.desc_ring[index].next = + htole32(sc->rx.desc_ring_paddr + DESC_OFF(RX_NEXT(index))); + sc->rx.desc_ring[index].status = htole32(status); +} + +static int +awg_setup_rxbuf(struct awg_softc *sc, int index, struct mbuf *m) +{ + bus_dma_segment_t seg; + int error, nsegs; + + m_adj(m, ETHER_ALIGN); + + error = bus_dmamap_load_mbuf_sg(sc->rx.buf_tag, + sc->rx.buf_map[index].map, m, &seg, &nsegs, 0); + if (error != 0) + return (error); + + bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map, + BUS_DMASYNC_PREREAD); + + sc->rx.buf_map[index].mbuf = m; + awg_setup_rxdesc(sc, index, seg.ds_addr); + + return (0); +} + +static struct mbuf * +awg_alloc_mbufcl(struct awg_softc *sc) +{ + struct mbuf *m; + + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (m != NULL) + m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; + + return (m); +} + +static void +awg_start_locked(struct awg_softc *sc) +{ + struct mbuf *m; + uint32_t val; + if_t ifp; + int cnt, nsegs; + + AWG_ASSERT_LOCKED(sc); + + if (!sc->link) + return; + + ifp = sc->ifp; + + if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) + return; + + for (cnt = 0; ; cnt++) { + if (sc->tx.queued >= TX_DESC_COUNT - TX_MAX_SEGS) { + if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); + break; + } + + m = if_dequeue(ifp); + if (m == NULL) + break; + + nsegs = awg_setup_txbuf(sc, sc->tx.cur, &m); + if (nsegs == 0) { + if_sendq_prepend(ifp, m); + break; + } + if_bpfmtap(ifp, m); + sc->tx.cur = TX_SKIP(sc->tx.cur, nsegs); + } + + if (cnt != 0) { + bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map, + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + + /* Start and run TX DMA */ + val = RD4(sc, EMAC_TX_CTL_1); + WR4(sc, EMAC_TX_CTL_1, val | TX_DMA_START); + } +} + +static void +awg_start(if_t ifp) +{ + struct awg_softc *sc; + + sc = if_getsoftc(ifp); + + AWG_LOCK(sc); + awg_start_locked(sc); + AWG_UNLOCK(sc); +} + +static void +awg_tick(void *softc) +{ + struct awg_softc *sc; + struct mii_data *mii; + if_t ifp; + int link; + + sc = softc; + ifp = sc->ifp; + mii = device_get_softc(sc->miibus); + + AWG_ASSERT_LOCKED(sc); + + if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) + return; + + link = sc->link; + mii_tick(mii); + if (sc->link && !link) + awg_start_locked(sc); + + callout_reset(&sc->stat_ch, hz, awg_tick, sc); +} + +/* Bit Reversal - http://aggregate.org/MAGIC/#Bit%20Reversal */ +static uint32_t +bitrev32(uint32_t x) +{ + x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); + x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); + x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); + x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); + + return (x >> 16) | (x << 16); +} + +static void +awg_setup_rxfilter(struct awg_softc *sc) +{ + uint32_t val, crc, hashreg, hashbit, hash[2], machi, maclo; + int mc_count, mcnt, i; + uint8_t *eaddr, *mta; + if_t ifp; + + AWG_ASSERT_LOCKED(sc); + + ifp = sc->ifp; + val = 0; + hash[0] = hash[1] = 0; + + mc_count = if_multiaddr_count(ifp, -1); + + if (if_getflags(ifp) & IFF_PROMISC) + val |= DIS_ADDR_FILTER; + else if (if_getflags(ifp) & IFF_ALLMULTI) { + val |= RX_ALL_MULTICAST; + hash[0] = hash[1] = ~0; + } else if (mc_count > 0) { + val |= HASH_MULTICAST; + + mta = malloc(sizeof(unsigned char) * ETHER_ADDR_LEN * mc_count, + M_DEVBUF, M_NOWAIT); + if (mta == NULL) { + if_printf(ifp, + "failed to allocate temporary multicast list\n"); + return; + } + + if_multiaddr_array(ifp, mta, &mcnt, mc_count); + for (i = 0; i < mcnt; i++) { + crc = ether_crc32_le(mta + (i * ETHER_ADDR_LEN), + ETHER_ADDR_LEN) & 0x7f; + crc = bitrev32(~crc) >> 26; + hashreg = (crc >> 5); + hashbit = (crc & 0x1f); + hash[hashreg] |= (1 << hashbit); + } + + free(mta, M_DEVBUF); + } + + /* Write our unicast address */ + eaddr = IF_LLADDR(ifp); + machi = (eaddr[5] << 8) | eaddr[4]; + maclo = (eaddr[3] << 24) | (eaddr[2] << 16) | (eaddr[1] << 8) | + (eaddr[0] << 0); + WR4(sc, EMAC_ADDR_HIGH(0), machi); + WR4(sc, EMAC_ADDR_LOW(0), maclo); + + /* Multicast hash filters */ + WR4(sc, EMAC_RX_HASH_0, hash[1]); + WR4(sc, EMAC_RX_HASH_1, hash[0]); + + /* RX frame filter config */ + WR4(sc, EMAC_RX_FRM_FLT, val); +} + +static void +awg_init_locked(struct awg_softc *sc) +{ + struct mii_data *mii; + uint32_t val; + if_t ifp; + + mii = device_get_softc(sc->miibus); + ifp = sc->ifp; + + AWG_ASSERT_LOCKED(sc); + + if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) + return; + + awg_setup_rxfilter(sc); + + /* Configure DMA burst length and priorities */ + val = awg_burst_len << BASIC_CTL_BURST_LEN_SHIFT; + if (awg_rx_tx_pri) + val |= BASIC_CTL_RX_TX_PRI; + WR4(sc, EMAC_BASIC_CTL_1, val); + + /* Enable interrupts */ + WR4(sc, EMAC_INT_EN, RX_INT_EN | TX_INT_EN | TX_BUF_UA_INT_EN); + + /* Enable transmit DMA */ + val = RD4(sc, EMAC_TX_CTL_1); + WR4(sc, EMAC_TX_CTL_1, val | TX_DMA_EN | TX_MD); + + /* Enable receive DMA */ + val = RD4(sc, EMAC_RX_CTL_1); + WR4(sc, EMAC_RX_CTL_1, val | RX_DMA_EN | RX_MD); + + /* Enable transmitter */ + val = RD4(sc, EMAC_TX_CTL_0); + WR4(sc, EMAC_TX_CTL_0, val | TX_EN); + + /* Enable receiver */ + val = RD4(sc, EMAC_RX_CTL_0); + WR4(sc, EMAC_RX_CTL_0, val | RX_EN | CHECK_CRC); + + if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); + + mii_mediachg(mii); + callout_reset(&sc->stat_ch, hz, awg_tick, sc); +} + +static void +awg_init(void *softc) +{ + struct awg_softc *sc; + + sc = softc; + + AWG_LOCK(sc); + awg_init_locked(sc); + AWG_UNLOCK(sc); +} + +static void +awg_stop(struct awg_softc *sc) +{ + if_t ifp; + uint32_t val; + + AWG_ASSERT_LOCKED(sc); + + ifp = sc->ifp; + + callout_stop(&sc->stat_ch); + + /* Stop transmit DMA and flush data in the TX FIFO */ + val = RD4(sc, EMAC_TX_CTL_1); + val &= ~TX_DMA_EN; + val |= FLUSH_TX_FIFO; + WR4(sc, EMAC_TX_CTL_1, val); + + /* Disable transmitter */ + val = RD4(sc, EMAC_TX_CTL_0); + WR4(sc, EMAC_TX_CTL_0, val & ~TX_EN); + + /* Disable receiver */ + val = RD4(sc, EMAC_RX_CTL_0); + WR4(sc, EMAC_RX_CTL_0, val & ~RX_EN); + + /* Disable interrupts */ + WR4(sc, EMAC_INT_EN, 0); + + /* Disable transmit DMA */ + val = RD4(sc, EMAC_TX_CTL_1); + WR4(sc, EMAC_TX_CTL_1, val & ~TX_DMA_EN); + + /* Disable receive DMA */ + val = RD4(sc, EMAC_RX_CTL_1); + WR4(sc, EMAC_RX_CTL_1, val & ~RX_DMA_EN); + + sc->link = 0; + + if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE); +} + +static void +awg_rxintr(struct awg_softc *sc) +{ + if_t ifp; + struct mbuf *m, *m0; + int error, index, len; + uint32_t status; + + ifp = sc->ifp; + + bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + for (index = sc->rx.cur; ; index = RX_NEXT(index)) { + status = le32toh(sc->rx.desc_ring[index].status); + if ((status & RX_DESC_CTL) != 0) + break; + + bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->rx.buf_tag, sc->rx.buf_map[index].map); + + len = (status & RX_FRM_LEN) >> RX_FRM_LEN_SHIFT; + if (len != 0) { + m = sc->rx.buf_map[index].mbuf; + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = len; + m->m_len = len; + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); + + if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0 && + (status & RX_FRM_TYPE) != 0) { + m->m_pkthdr.csum_flags = CSUM_IP_CHECKED; + if ((status & RX_HEADER_ERR) == 0) + m->m_pkthdr.csum_flags |= CSUM_IP_VALID; + if ((status & RX_PAYLOAD_ERR) == 0) { + m->m_pkthdr.csum_flags |= + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } + } + + AWG_UNLOCK(sc); + if_input(ifp, m); + AWG_LOCK(sc); + } + + if ((m0 = awg_alloc_mbufcl(sc)) != NULL) { + error = awg_setup_rxbuf(sc, index, m0); + if (error != 0) { + /* XXX hole in RX ring */ + } + } else + if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); + } + + if (index != sc->rx.cur) { + bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map, + BUS_DMASYNC_PREWRITE); + } + + sc->rx.cur = index; +} + +static void +awg_txintr(struct awg_softc *sc) +{ + struct awg_bufmap *bmap; + struct emac_desc *desc; + uint32_t status; + if_t ifp; + int i; + + AWG_ASSERT_LOCKED(sc); + + bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + ifp = sc->ifp; + for (i = sc->tx.next; sc->tx.queued > 0; i = TX_NEXT(i)) { + desc = &sc->tx.desc_ring[i]; + status = le32toh(desc->status); + if ((status & TX_DESC_CTL) != 0) + break; + bmap = &sc->tx.buf_map[i]; + if (bmap->mbuf != NULL) { + bus_dmamap_sync(sc->tx.buf_tag, bmap->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->tx.buf_tag, bmap->map); + m_freem(bmap->mbuf); + bmap->mbuf = NULL; + } + awg_setup_txdesc(sc, i, 0, 0, 0); + if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + } + + sc->tx.next = i; + + bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map, + BUS_DMASYNC_PREWRITE); +} + +static void +awg_intr(void *arg) +{ + struct awg_softc *sc; + uint32_t val; + + sc = arg; + + AWG_LOCK(sc); + val = RD4(sc, EMAC_INT_STA); + WR4(sc, EMAC_INT_STA, val); + + if (val & RX_INT) + awg_rxintr(sc); + + if (val & (TX_INT|TX_BUF_UA_INT)) { + awg_txintr(sc); + if (!if_sendq_empty(sc->ifp)) + awg_start_locked(sc); + } + + AWG_UNLOCK(sc); +} + +static int +awg_ioctl(if_t ifp, u_long cmd, caddr_t data) +{ + struct awg_softc *sc; + struct mii_data *mii; + struct ifreq *ifr; + int flags, mask, error; + + sc = if_getsoftc(ifp); + mii = device_get_softc(sc->miibus); + ifr = (struct ifreq *)data; + error = 0; + + switch (cmd) { + case SIOCSIFFLAGS: + AWG_LOCK(sc); + if (if_getflags(ifp) & IFF_UP) { + if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { + flags = if_getflags(ifp) ^ sc->if_flags; + if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0) + awg_setup_rxfilter(sc); + } else + awg_init_locked(sc); + } else { + if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) + awg_stop(sc); + } + sc->if_flags = if_getflags(ifp); + AWG_UNLOCK(sc); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { + AWG_LOCK(sc); + awg_setup_rxfilter(sc); + AWG_UNLOCK(sc); + } + break; + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); + break; + case SIOCSIFCAP: + mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); + if (mask & IFCAP_VLAN_MTU) + if_togglecapenable(ifp, IFCAP_VLAN_MTU); + if (mask & IFCAP_RXCSUM) + if_togglecapenable(ifp, IFCAP_RXCSUM); + if (mask & IFCAP_TXCSUM) + if_togglecapenable(ifp, IFCAP_TXCSUM); + if ((if_getcapenable(ifp) & (IFCAP_RXCSUM|IFCAP_TXCSUM)) != 0) + if_sethwassistbits(ifp, CSUM_IP, 0); + else + if_sethwassistbits(ifp, 0, CSUM_IP); + break; + default: + error = ether_ioctl(ifp, cmd, data); + break; + } + + return (error); +} + +static int +awg_setup_extres(device_t dev) +{ + struct awg_softc *sc; + hwreset_t rst_ahb; + clk_t clk_ahb, clk_tx, clk_tx_parent; + regulator_t reg; + const char *tx_parent_name; + char *phy_type; + phandle_t node; + uint64_t freq; + int error, div; + + sc = device_get_softc(dev); + node = ofw_bus_get_node(dev); + rst_ahb = NULL; + clk_ahb = NULL; + clk_tx = NULL; + clk_tx_parent = NULL; + reg = NULL; + phy_type = NULL; + + /* Get AHB clock and reset resources */ + error = hwreset_get_by_ofw_name(dev, "ahb", &rst_ahb); + if (error != 0) { + device_printf(dev, "cannot get ahb reset\n"); + goto fail; + } + error = clk_get_by_ofw_name(dev, "ahb", &clk_ahb); + if (error != 0) { + device_printf(dev, "cannot get ahb clock\n"); + goto fail; + } + + /* Configure PHY for MII or RGMII mode */ + if (OF_getprop_alloc(node, "phy-mode", 1, (void **)&phy_type)) { + if (bootverbose) + device_printf(dev, "PHY type: %s\n", phy_type); + + if (strcmp(phy_type, "rgmii") == 0) + tx_parent_name = "emac_int_tx"; + else + tx_parent_name = "mii_phy_tx"; + free(phy_type, M_OFWPROP); + + /* Get the TX clock */ + error = clk_get_by_ofw_name(dev, "tx", &clk_tx); + if (error != 0) { + device_printf(dev, "cannot get tx clock\n"); + goto fail; + } + + /* Find the desired parent clock based on phy-mode property */ + error = clk_get_by_name(dev, tx_parent_name, &clk_tx_parent); + if (error != 0) { + device_printf(dev, "cannot get clock '%s'\n", + tx_parent_name); + goto fail; + } + + /* Set TX clock parent */ + error = clk_set_parent_by_clk(clk_tx, clk_tx_parent); + if (error != 0) { + device_printf(dev, "cannot set tx clock parent\n"); + goto fail; + } + + /* Enable TX clock */ + error = clk_enable(clk_tx); + if (error != 0) { + device_printf(dev, "cannot enable tx clock\n"); + goto fail; + } + } + + /* Enable AHB clock */ + error = clk_enable(clk_ahb); + if (error != 0) { + device_printf(dev, "cannot enable ahb clock\n"); + goto fail; + } + + /* De-assert reset */ + error = hwreset_deassert(rst_ahb); + if (error != 0) { + device_printf(dev, "cannot de-assert ahb reset\n"); + goto fail; + } + + /* Enable PHY regulator if applicable */ + if (regulator_get_by_ofw_property(dev, "phy-supply", ®) == 0) { + error = regulator_enable(reg); + if (error != 0) { + device_printf(dev, "cannot enable PHY regulator\n"); + goto fail; + } + } + + /* Determine MDC clock divide ratio based on AHB clock */ + error = clk_get_freq(clk_ahb, &freq); + if (error != 0) { + device_printf(dev, "cannot get AHB clock frequency\n"); + goto fail; + } + div = freq / MDIO_FREQ; + if (div <= 16) + sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_16; + else if (div <= 32) + sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_32; + else if (div <= 64) + sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_64; + else if (div <= 128) + sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_128; + else { + device_printf(dev, "cannot determine MDC clock divide ratio\n"); + error = ENXIO; + goto fail; + } + + if (bootverbose) + device_printf(dev, "AHB frequency %llu Hz, MDC div: 0x%x\n", + freq, sc->mdc_div_ratio_m); + + return (0); + +fail: + free(phy_type, M_OFWPROP); + + if (reg != NULL) + regulator_release(reg); + if (clk_tx_parent != NULL) + clk_release(clk_tx_parent); + if (clk_tx != NULL) + clk_release(clk_tx); + if (clk_ahb != NULL) + clk_release(clk_ahb); + if (rst_ahb != NULL) + hwreset_release(rst_ahb); + return (error); +} + +static void +awg_get_eaddr(device_t dev, uint8_t *eaddr) +{ + struct awg_softc *sc; + uint32_t maclo, machi, rnd; + + sc = device_get_softc(dev); + + machi = RD4(sc, EMAC_ADDR_HIGH(0)) & 0xffff; + maclo = RD4(sc, EMAC_ADDR_LOW(0)); + + if (maclo == 0xffffffff && machi == 0xffff) { + /* MAC address in hardware is invalid, create one */ + rnd = arc4random(); + maclo = 0x00f2 | (rnd & 0xffff0000); + machi = rnd & 0xffff; + } + + eaddr[0] = maclo & 0xff; + eaddr[1] = (maclo >> 8) & 0xff; + eaddr[2] = (maclo >> 16) & 0xff; + eaddr[3] = (maclo >> 24) & 0xff; + eaddr[4] = machi & 0xff; + eaddr[5] = (machi >> 8) & 0xff; +} + +#ifdef AWG_DEBUG +static void +awg_dump_regs(device_t dev) +{ + static const struct { + const char *name; + u_int reg; + } regs[] = { + { "BASIC_CTL_0", EMAC_BASIC_CTL_0 }, + { "BASIC_CTL_1", EMAC_BASIC_CTL_1 }, + { "INT_STA", EMAC_INT_STA }, + { "INT_EN", EMAC_INT_EN }, + { "TX_CTL_0", EMAC_TX_CTL_0 }, + { "TX_CTL_1", EMAC_TX_CTL_1 }, + { "TX_FLOW_CTL", EMAC_TX_FLOW_CTL }, + { "TX_DMA_LIST", EMAC_TX_DMA_LIST }, + { "RX_CTL_0", EMAC_RX_CTL_0 }, + { "RX_CTL_1", EMAC_RX_CTL_1 }, + { "RX_DMA_LIST", EMAC_RX_DMA_LIST }, + { "RX_FRM_FLT", EMAC_RX_FRM_FLT }, + { "RX_HASH_0", EMAC_RX_HASH_0 }, + { "RX_HASH_1", EMAC_RX_HASH_1 }, + { "MII_CMD", EMAC_MII_CMD }, + { "ADDR_HIGH0", EMAC_ADDR_HIGH(0) }, + { "ADDR_LOW0", EMAC_ADDR_LOW(0) }, + { "TX_DMA_STA", EMAC_TX_DMA_STA }, + { "TX_DMA_CUR_DESC", EMAC_TX_DMA_CUR_DESC }, + { "TX_DMA_CUR_BUF", EMAC_TX_DMA_CUR_BUF }, + { "RX_DMA_STA", EMAC_RX_DMA_STA }, + { "RX_DMA_CUR_DESC", EMAC_RX_DMA_CUR_DESC }, + { "RX_DMA_CUR_BUF", EMAC_RX_DMA_CUR_BUF }, + { "RGMII_STA", EMAC_RGMII_STA }, + }; + struct awg_softc *sc; + unsigned int n; + + sc = device_get_softc(dev); + + for (n = 0; n < nitems(regs); n++) + device_printf(dev, " %-20s %08x\n", regs[n].name, + RD4(sc, regs[n].reg)); +} +#endif + +static int +awg_reset(device_t dev) +{ + struct awg_softc *sc; + int retry; + + sc = device_get_softc(dev); + + /* Soft reset all registers and logic */ + WR4(sc, EMAC_BASIC_CTL_1, BASIC_CTL_SOFT_RST); + + /* Wait for soft reset bit to self-clear */ + for (retry = SOFT_RST_RETRY; retry > 0; retry--) { + if ((RD4(sc, EMAC_BASIC_CTL_1) & BASIC_CTL_SOFT_RST) == 0) + break; + DELAY(10); + } + if (retry == 0) { + device_printf(dev, "soft reset timed out\n"); +#ifdef AWG_DEBUG + awg_dump_regs(dev); +#endif + return (ETIMEDOUT); + } + + return (0); +} + +static void +awg_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + if (error != 0) + return; + *(bus_addr_t *)arg = segs[0].ds_addr; +} + +static int +awg_setup_dma(device_t dev) +{ + struct awg_softc *sc; + struct mbuf *m; + int error, i; + + sc = device_get_softc(dev); + + /* Setup TX ring */ + error = bus_dma_tag_create( + bus_get_dma_tag(dev), /* Parent tag */ + DESC_ALIGN, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + TX_DESC_SIZE, 1, /* maxsize, nsegs */ + TX_DESC_SIZE, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->tx.desc_tag); + if (error != 0) { + device_printf(dev, "cannot create TX descriptor ring tag\n"); + return (error); + } + + error = bus_dmamem_alloc(sc->tx.desc_tag, (void **)&sc->tx.desc_ring, + BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->tx.desc_map); + if (error != 0) { + device_printf(dev, "cannot allocate TX descriptor ring\n"); + return (error); + } + + error = bus_dmamap_load(sc->tx.desc_tag, sc->tx.desc_map, + sc->tx.desc_ring, TX_DESC_SIZE, awg_dmamap_cb, + &sc->tx.desc_ring_paddr, 0); + if (error != 0) { + device_printf(dev, "cannot load TX descriptor ring\n"); + return (error); + } + + for (i = 0; i < TX_DESC_COUNT; i++) + sc->tx.desc_ring[i].next = + htole32(sc->tx.desc_ring_paddr + DESC_OFF(TX_NEXT(i))); + + error = bus_dma_tag_create( + bus_get_dma_tag(dev), /* Parent tag */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MCLBYTES, TX_MAX_SEGS, /* maxsize, nsegs */ + MCLBYTES, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->tx.buf_tag); + if (error != 0) { + device_printf(dev, "cannot create TX buffer tag\n"); + return (error); + } + + sc->tx.queued = TX_DESC_COUNT; + for (i = 0; i < TX_DESC_COUNT; i++) { + error = bus_dmamap_create(sc->tx.buf_tag, 0, + &sc->tx.buf_map[i].map); + if (error != 0) { + device_printf(dev, "cannot create TX buffer map\n"); + return (error); + } + awg_setup_txdesc(sc, i, 0, 0, 0); + } + + /* Setup RX ring */ + error = bus_dma_tag_create( + bus_get_dma_tag(dev), /* Parent tag */ + DESC_ALIGN, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + RX_DESC_SIZE, 1, /* maxsize, nsegs */ + RX_DESC_SIZE, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->rx.desc_tag); + if (error != 0) { + device_printf(dev, "cannot create RX descriptor ring tag\n"); + return (error); + } + + error = bus_dmamem_alloc(sc->rx.desc_tag, (void **)&sc->rx.desc_ring, + BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->rx.desc_map); + if (error != 0) { + device_printf(dev, "cannot allocate RX descriptor ring\n"); + return (error); + } + + error = bus_dmamap_load(sc->rx.desc_tag, sc->rx.desc_map, + sc->rx.desc_ring, RX_DESC_SIZE, awg_dmamap_cb, + &sc->rx.desc_ring_paddr, 0); + if (error != 0) { + device_printf(dev, "cannot load RX descriptor ring\n"); + return (error); + } + + error = bus_dma_tag_create( + bus_get_dma_tag(dev), /* Parent tag */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MCLBYTES, 1, /* maxsize, nsegs */ + MCLBYTES, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->rx.buf_tag); + if (error != 0) { + device_printf(dev, "cannot create RX buffer tag\n"); + return (error); + } + + for (i = 0; i < RX_DESC_COUNT; i++) { + error = bus_dmamap_create(sc->rx.buf_tag, 0, + &sc->rx.buf_map[i].map); + if (error != 0) { + device_printf(dev, "cannot create RX buffer map\n"); + return (error); + } + if ((m = awg_alloc_mbufcl(sc)) == NULL) { + device_printf(dev, "cannot allocate RX mbuf\n"); + return (ENOMEM); + } + error = awg_setup_rxbuf(sc, i, m); + if (error != 0) { + device_printf(dev, "cannot create RX buffer\n"); + return (error); + } + } + bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map, + BUS_DMASYNC_PREWRITE); + + /* Write transmit and receive descriptor base address registers */ + WR4(sc, EMAC_TX_DMA_LIST, sc->tx.desc_ring_paddr); + WR4(sc, EMAC_RX_DMA_LIST, sc->rx.desc_ring_paddr); + + return (0); +} + +static int +awg_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "Allwinner Gigabit Ethernet"); + return (BUS_PROBE_DEFAULT); +} + +static int +awg_attach(device_t dev) +{ + uint8_t eaddr[ETHER_ADDR_LEN]; + struct awg_softc *sc; + phandle_t node; + int error; + + sc = device_get_softc(dev); + node = ofw_bus_get_node(dev); + + if (bus_alloc_resources(dev, awg_spec, sc->res) != 0) { + device_printf(dev, "cannot allocate resources for device\n"); + return (ENXIO); + } + + mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); + callout_init_mtx(&sc->stat_ch, &sc->mtx, 0); + TASK_INIT(&sc->link_task, 0, awg_link_task, sc); + + /* Setup clocks and regulators */ + error = awg_setup_extres(dev); + if (error != 0) + return (error); + + /* Read MAC address before resetting the chip */ + awg_get_eaddr(dev, eaddr); + + /* Soft reset EMAC core */ + error = awg_reset(dev); + if (error != 0) + return (error); + + /* Setup DMA descriptors */ + error = awg_setup_dma(dev); + if (error != 0) + return (error); + + /* Install interrupt handler */ + error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, + NULL, awg_intr, sc, &sc->ih); + if (error != 0) { + device_printf(dev, "cannot setup interrupt handler\n"); + return (error); + } + + /* Setup ethernet interface */ + sc->ifp = if_alloc(IFT_ETHER); + if_setsoftc(sc->ifp, sc); + if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev)); + if_setflags(sc->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); + if_setstartfn(sc->ifp, awg_start); + if_setioctlfn(sc->ifp, awg_ioctl); + if_setinitfn(sc->ifp, awg_init); + if_setsendqlen(sc->ifp, TX_DESC_COUNT - 1); + if_setsendqready(sc->ifp); + if_sethwassist(sc->ifp, CSUM_IP | CSUM_UDP | CSUM_TCP); + if_setcapabilities(sc->ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM); + if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp)); + + /* Attach MII driver */ + error = mii_attach(dev, &sc->miibus, sc->ifp, awg_media_change, + awg_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, + MIIF_DOPAUSE); + if (error != 0) { + device_printf(dev, "cannot attach PHY\n"); + return (error); + } + + /* Attach ethernet interface */ + ether_ifattach(sc->ifp, eaddr); + + return (0); +} + +static device_method_t awg_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, awg_probe), + DEVMETHOD(device_attach, awg_attach), + + /* MII interface */ + DEVMETHOD(miibus_readreg, awg_miibus_readreg), + DEVMETHOD(miibus_writereg, awg_miibus_writereg), + DEVMETHOD(miibus_statchg, awg_miibus_statchg), + + DEVMETHOD_END +}; + +static driver_t awg_driver = { + "awg", + awg_methods, + sizeof(struct awg_softc), +}; + +static devclass_t awg_devclass; + +DRIVER_MODULE(awg, simplebus, awg_driver, awg_devclass, 0, 0); +DRIVER_MODULE(miibus, awg, miibus_driver, miibus_devclass, 0, 0); + +MODULE_DEPEND(awg, ether, 1, 1, 1); +MODULE_DEPEND(awg, miibus, 1, 1, 1); diff --git a/sys/arm/allwinner/if_awgreg.h b/sys/arm/allwinner/if_awgreg.h new file mode 100644 index 0000000..53a15c1 --- /dev/null +++ b/sys/arm/allwinner/if_awgreg.h @@ -0,0 +1,181 @@ +/*- + * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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 + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Allwinner Gigabit Ethernet + */ + +#ifndef __IF_AWGREG_H__ +#define __IF_AWGREG_H__ + +#define EMAC_BASIC_CTL_0 0x00 +#define BASIC_CTL_SPEED (0x3 << 2) +#define BASIC_CTL_SPEED_SHIFT 2 +#define BASIC_CTL_SPEED_1000 0 +#define BASIC_CTL_SPEED_10 2 +#define BASIC_CTL_SPEED_100 3 +#define BASIC_CTL_LOOPBACK (1 << 1) +#define BASIC_CTL_DUPLEX (1 << 0) +#define EMAC_BASIC_CTL_1 0x04 +#define BASIC_CTL_BURST_LEN (0x3f << 24) +#define BASIC_CTL_BURST_LEN_SHIFT 24 +#define BASIC_CTL_RX_TX_PRI (1 << 1) +#define BASIC_CTL_SOFT_RST (1 << 0) +#define EMAC_INT_STA 0x08 +#define RX_BUF_UA_INT (1 << 10) +#define RX_INT (1 << 8) +#define TX_UNDERFLOW_INT (1 << 4) +#define TX_BUF_UA_INT (1 << 2) +#define TX_DMA_STOPPED_INT (1 << 1) +#define TX_INT (1 << 0) +#define EMAC_INT_EN 0x0c +#define RX_BUF_UA_INT_EN (1 << 10) +#define RX_INT_EN (1 << 8) +#define TX_UNDERFLOW_INT_EN (1 << 4) +#define TX_BUF_UA_INT_EN (1 << 2) +#define TX_DMA_STOPPED_INT_EN (1 << 1) +#define TX_INT_EN (1 << 0) +#define EMAC_TX_CTL_0 0x10 +#define TX_EN (1 << 31) +#define EMAC_TX_CTL_1 0x14 +#define TX_DMA_START (1 << 31) +#define TX_DMA_EN (1 << 30) +#define TX_MD (1 << 1) +#define FLUSH_TX_FIFO (1 << 0) +#define EMAC_TX_FLOW_CTL 0x1c +#define PAUSE_TIME (0xffff << 4) +#define PAUSE_TIME_SHIFT 4 +#define TX_FLOW_CTL_EN (1 << 0) +#define EMAC_TX_DMA_LIST 0x20 +#define EMAC_RX_CTL_0 0x24 +#define RX_EN (1 << 31) +#define JUMBO_FRM_EN (1 << 29) +#define STRIP_FCS (1 << 28) +#define CHECK_CRC (1 << 27) +#define RX_FLOW_CTL_EN (1 << 16) +#define EMAC_RX_CTL_1 0x28 +#define RX_DMA_START (1 << 31) +#define RX_DMA_EN (1 << 30) +#define RX_MD (1 << 1) +#define EMAC_RX_DMA_LIST 0x34 +#define EMAC_RX_FRM_FLT 0x38 +#define DIS_ADDR_FILTER (1 << 31) +#define DIS_BROADCAST (1 << 17) +#define RX_ALL_MULTICAST (1 << 16) +#define CTL_FRM_FILTER (0x3 << 12) +#define CTL_FRM_FILTER_SHIFT 12 +#define HASH_MULTICAST (1 << 9) +#define HASH_UNICAST (1 << 8) +#define SA_FILTER_EN (1 << 6) +#define SA_INV_FILTER (1 << 5) +#define DA_INV_FILTER (1 << 4) +#define FLT_MD (1 << 1) +#define RX_ALL (1 << 0) +#define EMAC_RX_HASH_0 0x40 +#define EMAC_RX_HASH_1 0x44 +#define EMAC_MII_CMD 0x48 +#define MDC_DIV_RATIO_M (0x7 << 20) +#define MDC_DIV_RATIO_M_16 0 +#define MDC_DIV_RATIO_M_32 1 +#define MDC_DIV_RATIO_M_64 2 +#define MDC_DIV_RATIO_M_128 3 +#define MDC_DIV_RATIO_M_SHIFT 20 +#define PHY_ADDR (0x1f << 12) +#define PHY_ADDR_SHIFT 12 +#define PHY_REG_ADDR (0x1f << 4) +#define PHY_REG_ADDR_SHIFT 4 +#define MII_WR (1 << 1) +#define MII_BUSY (1 << 0) +#define EMAC_MII_DATA 0x4c +#define EMAC_ADDR_HIGH(n) (0x50 + (n) * 8) +#define EMAC_ADDR_LOW(n) (0x54 + (n) * 8) +#define EMAC_TX_DMA_STA 0x80 +#define EMAC_TX_DMA_CUR_DESC 0x84 +#define EMAC_TX_DMA_CUR_BUF 0x88 +#define EMAC_RX_DMA_STA 0xc0 +#define EMAC_RX_DMA_CUR_DESC 0xc4 +#define EMAC_RX_DMA_CUR_BUF 0xc8 +#define EMAC_RGMII_STA 0xd0 + +struct emac_desc { + uint32_t status; +/* Transmit */ +#define TX_DESC_CTL (1 << 31) +#define TX_HEADER_ERR (1 << 16) +#define TX_LENGTH_ERR (1 << 14) +#define TX_PAYLOAD_ERR (1 << 12) +#define TX_CRS_ERR (1 << 10) +#define TX_COL_ERR_0 (1 << 9) +#define TX_COL_ERR_1 (1 << 8) +#define TX_COL_CNT (0xf << 3) +#define TX_COL_CNT_SHIFT 3 +#define TX_DEFER_ERR (1 << 2) +#define TX_UNDERFLOW_ERR (1 << 1) +#define TX_DEFER (1 << 0) +/* Receive */ +#define RX_DESC_CTL (1 << 31) +#define RX_DAF_FAIL (1 << 30) +#define RX_FRM_LEN (0x3fff << 16) +#define RX_FRM_LEN_SHIFT 16 +#define RX_NO_ENOUGH_BUF_ERR (1 << 14) +#define RX_SAF_FAIL (1 << 13) +#define RX_OVERFLOW_ERR (1 << 11) +#define RX_FIR_DESC (1 << 9) +#define RX_LAST_DESC (1 << 8) +#define RX_HEADER_ERR (1 << 7) +#define RX_COL_ERR (1 << 6) +#define RX_FRM_TYPE (1 << 5) +#define RX_LENGTH_ERR (1 << 4) +#define RX_PHY_ERR (1 << 3) +#define RX_CRC_ERR (1 << 1) +#define RX_PAYLOAD_ERR (1 << 0) + + uint32_t size; +/* Transmit */ +#define TX_INT_CTL (1 << 31) +#define TX_LAST_DESC (1 << 30) +#define TX_FIR_DESC (1 << 29) +#define TX_CHECKSUM_CTL (0x3 << 27) +#define TX_CHECKSUM_CTL_IP 1 +#define TX_CHECKSUM_CTL_NO_PSE 2 +#define TX_CHECKSUM_CTL_FULL 3 +#define TX_CHECKSUM_CTL_SHIFT 27 +#define TX_CRC_CTL (1 << 26) +#define TX_BUF_SIZE (0xfff << 0) +#define TX_BUF_SIZE_SHIFT 0 +/* Receive */ +#define RX_INT_CTL (1 << 31) +#define RX_BUF_SIZE (0xfff << 0) +#define RX_BUF_SIZE_SHIFT 0 + + uint32_t addr; + + uint32_t next; +} __packed; + +#endif /* !__IF_AWGREG_H__ */ diff --git a/sys/arm/allwinner/std.allwinner b/sys/arm/allwinner/std.allwinner index 885d41d..5ac9dd6 100644 --- a/sys/arm/allwinner/std.allwinner +++ b/sys/arm/allwinner/std.allwinner @@ -14,3 +14,4 @@ options IPI_IRQ_END=15 files "../allwinner/files.allwinner" files "../allwinner/a20/files.a20" files "../allwinner/a31/files.a31" +files "../allwinner/a83t/files.a83t" diff --git a/sys/arm/amlogic/aml8726/aml8726_mmc.c b/sys/arm/amlogic/aml8726/aml8726_mmc.c index 0e24975..5205507 100644 --- a/sys/arm/amlogic/aml8726/aml8726_mmc.c +++ b/sys/arm/amlogic/aml8726/aml8726_mmc.c @@ -240,7 +240,7 @@ aml8726_mmc_start_command(struct aml8726_mmc_softc *sc, struct mmc_command *cmd) * Start and transmission bits are per section 4.7.2 of the: * * SD Specifications Part 1 - * Physicaly Layer Simplified Specification + * Physical Layer Simplified Specification * Version 4.10 */ cmdr = AML_MMC_CMD_START_BIT | AML_MMC_CMD_TRANS_BIT_HOST | cmd->opcode; diff --git a/sys/arm/amlogic/aml8726/aml8726_mmc.h b/sys/arm/amlogic/aml8726/aml8726_mmc.h index 64e3bae..a2dde21 100644 --- a/sys/arm/amlogic/aml8726/aml8726_mmc.h +++ b/sys/arm/amlogic/aml8726/aml8726_mmc.h @@ -39,7 +39,7 @@ * Read and write are per section 4.6.2 of the: * * SD Specifications Part 1 - * Physicaly Layer Simplified Specification + * Physical Layer Simplified Specification * Version 4.10 */ #define AML_MMC_CMD_TIMEOUT 50 diff --git a/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.c b/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.c index 75825fb..a5be5e4 100644 --- a/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.c +++ b/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.c @@ -484,7 +484,7 @@ aml8726_sdxc_finish_command(struct aml8726_sdxc_softc *sc, int mmc_error) if (stop_cmd != NULL) { /* - * If the original command executed successfuly, then + * If the original command executed successfully, then * the hardware will also have automatically executed * a stop command so don't bother with the one supplied * with the original request. diff --git a/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.h b/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.h index 013a86e..1d0dc14 100644 --- a/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.h +++ b/sys/arm/amlogic/aml8726/aml8726_sdxc-m8.h @@ -38,7 +38,7 @@ * Read and write are per section 4.6.2 of the: * * SD Specifications Part 1 - * Physicaly Layer Simplified Specification + * Physical Layer Simplified Specification * Version 4.10 */ #define AML_SDXC_CMD_TIMEOUT 50 diff --git a/sys/arm/arm/cpufunc_asm_arm11.S b/sys/arm/arm/cpufunc_asm_arm11.S index f83f819..d6538c6 100644 --- a/sys/arm/arm/cpufunc_asm_arm11.S +++ b/sys/arm/arm/cpufunc_asm_arm11.S @@ -30,7 +30,7 @@ * * ARM11 assembly functions for CPU / MMU / TLB specific operations * - * XXX We make no attempt at present to take advantage of the v6 memroy + * XXX We make no attempt at present to take advantage of the v6 memory * architecture or physically tagged cache. */ diff --git a/sys/arm/arm/exception.S b/sys/arm/arm/exception.S index 9f186a5..9466cf6 100644 --- a/sys/arm/arm/exception.S +++ b/sys/arm/arm/exception.S @@ -175,7 +175,7 @@ _C_LABEL(dtrace_invop_jump_addr): ldr r4, [r5, #4]; /* reset it to point at the */ \ cmp r4, #0xffffffff; /* end of memory if necessary; */ \ movne r1, #0xffffffff; /* leave value in r4 for later */ \ - strne r1, [r5, #4]; /* comparision against PC. */ \ + strne r1, [r5, #4]; /* comparison against PC. */ \ ldr r3, [r5]; /* Retrieve global RAS_START */ \ cmp r3, #0; /* and reset it if non-zero. */ \ movne r1, #0; /* If non-zero RAS_START and */ \ diff --git a/sys/arm/arm/genassym.c b/sys/arm/arm/genassym.c index f9cb23e..9c67018 100644 --- a/sys/arm/arm/genassym.c +++ b/sys/arm/arm/genassym.c @@ -28,6 +28,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/cpuset.h> #include <sys/systm.h> #include <sys/assym.h> #include <sys/proc.h> diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c index 6e6fcea..dcf48bc 100644 --- a/sys/arm/arm/generic_timer.c +++ b/sys/arm/arm/generic_timer.c @@ -100,7 +100,7 @@ static struct arm_tmr_softc *arm_tmr_sc = NULL; static struct resource_spec timer_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Secure */ { SYS_RES_IRQ, 1, RF_ACTIVE }, /* Non-secure */ - { SYS_RES_IRQ, 2, RF_ACTIVE }, /* Virt */ + { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, /* Virt */ { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, /* Hyp */ { -1, 0 } }; @@ -392,13 +392,17 @@ arm_tmr_attach(device_t dev) #ifdef __arm__ sc->physical = true; #else /* __aarch64__ */ - sc->physical = false; + /* If we do not have a virtual timer use the physical. */ + sc->physical = (sc->res[2] == NULL) ? true : false; #endif arm_tmr_sc = sc; /* Setup secure, non-secure and virtual IRQs handler */ for (i = 0; i < 3; i++) { + /* If we do not have the interrupt, skip it. */ + if (sc->res[i] == NULL) + continue; error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, arm_tmr_intr, NULL, sc, &sc->ihl[i]); if (error) { @@ -417,7 +421,7 @@ arm_tmr_attach(device_t dev) sc->et.et_quality = 1000; sc->et.et_frequency = sc->clkfreq; - sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; + sc->et.et_min_period = (0x00000010LLU << 32) / sc->et.et_frequency; sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = arm_tmr_start; sc->et.et_stop = arm_tmr_stop; diff --git a/sys/arm/arm/gic.c b/sys/arm/arm/gic.c index 08693d9..17e1525 100644 --- a/sys/arm/arm/gic.c +++ b/sys/arm/arm/gic.c @@ -1006,18 +1006,22 @@ gic_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp, enum intr_polarity pol; enum intr_trigger trig; struct arm_gic_softc *sc; +#ifdef FDT + struct intr_map_data_fdt *daf; +#endif sc = device_get_softc(dev); switch (data->type) { #ifdef FDT case INTR_MAP_DATA_FDT: - if (gic_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq, - &pol, &trig) != 0) + daf = (struct intr_map_data_fdt *)data; + if (gic_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol, + &trig) != 0) return (EINVAL); break; #endif default: - return (EINVAL); + return (ENOTSUP); } if (irq >= sc->nirqs) @@ -1231,7 +1235,7 @@ arm_gic_next_irq(struct arm_gic_softc *sc, int last_irq) active_irq = gic_c_read_4(sc, GICC_IAR); /* - * Immediatly EOIR the SGIs, because doing so requires the other + * Immediately EOIR the SGIs, because doing so requires the other * bits (ie CPU number), not just the IRQ number, and we do not * have this information later. */ diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c index 453c197..49d5986 100644 --- a/sys/arm/arm/machdep.c +++ b/sys/arm/arm/machdep.c @@ -36,7 +36,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Machine dependant functions for kernel setup + * Machine dependent functions for kernel setup * * Created : 17/09/94 * Updated : 18/04/01 updated for new wscons diff --git a/sys/arm/arm/mpcore_timer.c b/sys/arm/arm/mpcore_timer.c index fb30d38..03f8e4b 100644 --- a/sys/arm/arm/mpcore_timer.c +++ b/sys/arm/arm/mpcore_timer.c @@ -367,7 +367,7 @@ attach_et(struct arm_tmr_softc *sc) * globally and registers both the timecount and eventtimer objects. * * RETURNS - * Zero on sucess or ENXIO if an error occuried. + * Zero on success or ENXIO if an error occuried. */ static int arm_tmr_attach(device_t dev) @@ -457,7 +457,7 @@ EARLY_DRIVER_MODULE(mp_tmr, ofwbus, arm_tmr_driver, arm_tmr_devclass, 0, 0, /* * Handle a change in clock frequency. The mpcore timer runs at half the CPU * frequency. When the CPU frequency changes due to power-saving or thermal - * managment, the platform-specific code that causes the frequency change calls + * management, the platform-specific code that causes the frequency change calls * this routine to inform the clock driver, and we in turn inform the event * timer system, which actually updates the value in et->frequency for us and * reschedules the current event(s) in a way that's atomic with respect to diff --git a/sys/arm/arm/pmap-v4.c b/sys/arm/arm/pmap-v4.c index 733ccf2..3bdc9e4 100644 --- a/sys/arm/arm/pmap-v4.c +++ b/sys/arm/arm/pmap-v4.c @@ -126,7 +126,7 @@ * * pmap.c * - * Machine dependant vm stuff + * Machine dependent vm stuff * * Created : 20/09/94 */ @@ -1386,9 +1386,9 @@ pmap_clearbit(struct vm_page *pg, u_int maskbits) * * Don't turn caching on again if this is a * modified emulation. This would be - * inconsitent with the settings created by + * inconsistent with the settings created by * pmap_fix_cache(). Otherwise, it's safe - * to re-enable cacheing. + * to re-enable caching. * * There's no need to call pmap_fix_cache() * here: all pages are losing their write diff --git a/sys/arm/arm/pmap-v6.c b/sys/arm/arm/pmap-v6.c index f5a6fa8..703f39d 100644 --- a/sys/arm/arm/pmap-v6.c +++ b/sys/arm/arm/pmap-v6.c @@ -705,7 +705,7 @@ pmap_preboot_get_pages(u_int num) } /* - * The fundamental initalization of PMAP stuff. + * The fundamental initialization of PMAP stuff. * * Some things already happened in locore.S and some things could happen * before pmap_bootstrap_prepare() is called, so let's recall what is done: @@ -1210,7 +1210,7 @@ pmap_bootstrap(vm_offset_t firstaddr) /* * Note that in very short time in initarm(), we are going to - * initialize phys_avail[] array and no futher page allocation + * initialize phys_avail[] array and no further page allocation * can happen after that until vm subsystem will be initialized. */ kernel_vm_end_new = kernel_vm_end; diff --git a/sys/arm/arm/swtch-v4.S b/sys/arm/arm/swtch-v4.S index 6fdbeed..21924dc 100644 --- a/sys/arm/arm/swtch-v4.S +++ b/sys/arm/arm/swtch-v4.S @@ -296,7 +296,7 @@ ENTRY(cpu_switch) beq .Lcs_context_switched /* yes! */ /* - * Definately need to flush the cache. + * Definitely need to flush the cache. */ ldr r1, .Lcpufuncs diff --git a/sys/arm/at91/at91_cfata.c b/sys/arm/at91/at91_cfata.c index 37ce434..d4848ff 100644 --- a/sys/arm/at91/at91_cfata.c +++ b/sys/arm/at91/at91_cfata.c @@ -26,7 +26,7 @@ * common memory mode. Interrupts are driven by polling. The driver * implements an ATA bridge and attached ATA channel driver on top * of it. - * NOTE WELL: this driver uses polling mode. To achive an acceptable + * NOTE WELL: this driver uses polling mode. To achieve an acceptable * operating speed you will probably want to use HZ=2000 in kernel * config. */ diff --git a/sys/arm/at91/at91_machdep.c b/sys/arm/at91/at91_machdep.c index b6ff9ca..6be7f72 100644 --- a/sys/arm/at91/at91_machdep.c +++ b/sys/arm/at91/at91_machdep.c @@ -36,7 +36,7 @@ * * machdep.c * - * Machine dependant functions for kernel setup + * Machine dependent functions for kernel setup * * This file needs a lot of work. * diff --git a/sys/arm/at91/at91_mci.c b/sys/arm/at91/at91_mci.c index cf884b9..bb5b7d5 100644 --- a/sys/arm/at91/at91_mci.c +++ b/sys/arm/at91/at91_mci.c @@ -92,7 +92,7 @@ __FBSDID("$FreeBSD$"); * speed is 25MHz and the next highest speed is 15MHz or less. This appears * to work on virtually all SD cards, since it is what this driver has been * doing prior to the introduction of this option, where the overclocking vs - * underclocking decision was automaticly "overclock". Modern SD cards can + * underclocking decision was automatically "overclock". Modern SD cards can * run at 45mhz/1-bit in standard mode (high speed mode enable commands not * sent) without problems. * @@ -212,7 +212,7 @@ at91_bswap_buf(struct at91_mci_softc *sc, void * dptr, void * sptr, uint32_t mem /* * If the hardware doesn't need byte-swapping, let bcopy() do the * work. Use bounce buffer even if we don't need byteswap, since - * buffer may straddle a page boundry, and we don't handle + * buffer may straddle a page boundary, and we don't handle * multi-segment transfers in hardware. Seen from 'bsdlabel -w' which * uses raw geom access to the volume. Greg Ansley (gja (at) * ansley.com) diff --git a/sys/arm/at91/at91_reset.S b/sys/arm/at91/at91_reset.S index 28703cc..36d72e4 100644 --- a/sys/arm/at91/at91_reset.S +++ b/sys/arm/at91/at91_reset.S @@ -14,7 +14,7 @@ __FBSDID("$FreeBSD$"); /* * From AT91SAM9G20 Datasheet errata 44:3.5: * - * When User Reset occurs durring SDRAM read acces, eh SDRAM clock is turned + * When User Reset occurs during SDRAM read access, the SDRAM clock is turned * off while data are ready to be read on the data bus. The SDRAM maintains * the data until the clock restarts. * diff --git a/sys/arm/at91/at91reg.h b/sys/arm/at91/at91reg.h index e0aaa81..35e14f5 100644 --- a/sys/arm/at91/at91reg.h +++ b/sys/arm/at91/at91reg.h @@ -39,9 +39,9 @@ #define AT91_PA_BASE 0xf0000000 /* A few things that we count on being the same - * throught the whole family of SOCs */ + * throughout the whole family of SOCs */ -/* SYSC System Controler */ +/* SYSC System Controller */ /* System Registers */ #define AT91_SYS_BASE 0xffff000 #define AT91_SYS_SIZE 0x1000 diff --git a/sys/arm/at91/at91sam9260.c b/sys/arm/at91/at91sam9260.c index 5b0f537..4514d87 100644 --- a/sys/arm/at91/at91sam9260.c +++ b/sys/arm/at91/at91sam9260.c @@ -188,7 +188,7 @@ at91_clock_init(void) * PMC alogrithm choose the divisor that causes the input clock * to be near the optimal 2 MHz per datasheet. We know * we are going to be using this for the USB clock at 96 MHz. - * Causes no extra frequency deviation for all recomended crystal + * Causes no extra frequency deviation for all recommended crystal * values. See Note 1, table 40-16 SAM9260 doc. */ clk = at91_pmc_clock_ref("pllb"); diff --git a/sys/arm/at91/if_ate.c b/sys/arm/at91/if_ate.c index 082b24f..fdca46b 100644 --- a/sys/arm/at91/if_ate.c +++ b/sys/arm/at91/if_ate.c @@ -651,7 +651,7 @@ ate_activate(device_t dev) ate_getaddr, &sc->tx_desc_phys, 0) != 0) goto errout; - /* Initilize descriptors; mark all empty */ + /* Initialize descriptors; mark all empty */ for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) { sc->tx_descs[i].addr =0; sc->tx_descs[i].status = ETHB_TX_USED; @@ -919,7 +919,7 @@ ate_intr(void *xsc) /* * Simulate SAM9 FIRST/LAST bits for RM9200. * RM9200 EMAC has only on Rx buffer per packet. - * But sometime we are handed a zero lenght packet. + * But sometime we are handed a zero length packet. */ if ((rxdhead->status & ETH_LEN_MASK) == 0) rxdhead->status = 0; /* Mark error */ @@ -980,7 +980,7 @@ ate_intr(void *xsc) do { /* Last buffer may just be 1-4 bytes of FCS so remain - * may be zero for last decriptor. */ + * may be zero for last descriptor. */ if (remain > 0) { /* Make sure we get the current bytes */ bus_dmamap_sync(sc->rx_tag, sc->rx_map[sc->rxhead], @@ -989,7 +989,7 @@ ate_intr(void *xsc) count = MIN(remain, sc->rx_buf_size); /* XXX Performance robbing copy. Could - * recieve directly to mbufs if not an + * receive directly to mbufs if not an * RM9200. And even then we could likely * copy just the protocol headers. XXX */ m_append(mb, count, sc->rx_buf[sc->rxhead]); @@ -1468,7 +1468,7 @@ ate_miibus_readreg(device_t dev, int phy, int reg) int val; /* - * XXX if we implement agressive power savings, then we need + * XXX if we implement aggressive power savings, then we need * XXX to make sure that the clock to the emac is on here */ @@ -1488,7 +1488,7 @@ ate_miibus_writereg(device_t dev, int phy, int reg, int data) struct ate_softc *sc; /* - * XXX if we implement agressive power savings, then we need + * XXX if we implement aggressive power savings, then we need * XXX to make sure that the clock to the emac is on here */ diff --git a/sys/arm/at91/if_atereg.h b/sys/arm/at91/if_atereg.h index fc7e4de..c6cbbcf 100644 --- a/sys/arm/at91/if_atereg.h +++ b/sys/arm/at91/if_atereg.h @@ -28,7 +28,7 @@ #ifndef ARM_AT91_IF_ATEREG_H #define ARM_AT91_IF_ATEREG_H -/* deines begining ETHB_ are EMACB (newer SAM9 hardware) versions only */ +/* Defines beginning ETHB_ are EMACB (newer SAM9 hardware) versions only. */ #define ETH_CTL 0x00 /* EMAC Control Register */ #define ETH_CFG 0x04 /* EMAC Configuration Register */ @@ -191,7 +191,7 @@ typedef struct { #define ETH_MAC_LOCAL_3 (1U << 24) /* Packet matched addr 3 */ #define ETH_MAC_LOCAL_2 (1U << 25) /* Packet matched addr 2 */ #define ETH_MAC_LOCAL_1 (1U << 26) /* Packet matched addr 1 */ -#define ETH_MAC_UNK (1U << 27) /* Unkown source address RFU */ +#define ETH_MAC_UNK (1U << 27) /* Unknown source address RFU */ #define ETH_MAC_EXT (1U << 28) /* External Address */ #define ETH_MAC_UCAST (1U << 29) /* Unicast hash match */ #define ETH_MAC_MCAST (1U << 30) /* Multicast hash match */ diff --git a/sys/arm/broadcom/bcm2835/bcm2835_audio.c b/sys/arm/broadcom/bcm2835/bcm2835_audio.c index bfed287..8658c26 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_audio.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_audio.c @@ -828,7 +828,7 @@ bcm2835_audio_attach(device_t dev) /* * We need interrupts enabled for VCHI to work properly, - * so delay intialization until it happens + * so delay initialization until it happens. */ sc->intr_hook.ich_func = bcm2835_audio_delayed_init; sc->intr_hook.ich_arg = sc; diff --git a/sys/arm/broadcom/bcm2835/bcm2835_dma.c b/sys/arm/broadcom/bcm2835/bcm2835_dma.c index 347be2b..f174701 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_dma.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_dma.c @@ -278,7 +278,7 @@ bcm_dma_init(device_t dev) /* * Least alignment for busdma-allocated stuff is cache - * line size, so just make sure nothing stupid happend + * line size, so just make sure nothing stupid happened * and we got properly aligned address */ if ((uintptr_t)cb_virt & 0x1f) { @@ -539,7 +539,7 @@ bcm_dma_reg_dump(int ch) * ch - channel number * src, dst - source and destination address in * ARM physical memory address space. - * len - amount of bytes to be transfered + * len - amount of bytes to be transferred * * Returns 0 on success, -1 otherwise */ diff --git a/sys/arm/broadcom/bcm2835/bcm2835_gpio.c b/sys/arm/broadcom/bcm2835/bcm2835_gpio.c index 7c67a38..9619503 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_gpio.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_gpio.c @@ -67,8 +67,16 @@ __FBSDID("$FreeBSD$"); #define BCM_GPIO_IRQS 4 #define BCM_GPIO_PINS 54 #define BCM_GPIO_PINS_PER_BANK 32 + +#ifdef INTRNG +#define BCM_GPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ + GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_INTR_LEVEL_LOW | \ + GPIO_INTR_LEVEL_HIGH | GPIO_INTR_EDGE_RISING | \ + GPIO_INTR_EDGE_FALLING | GPIO_INTR_EDGE_BOTH) +#else #define BCM_GPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN) +#endif static struct resource_spec bcm_gpio_res_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, @@ -88,7 +96,7 @@ struct bcm_gpio_sysctl { struct bcm_gpio_irqsrc { struct intr_irqsrc bgi_isrc; uint32_t bgi_irq; - uint32_t bgi_reg; + uint32_t bgi_mode; uint32_t bgi_mask; }; #endif @@ -894,6 +902,17 @@ bcm_gpio_detach(device_t dev) #ifdef INTRNG static inline void +bcm_gpio_modify(struct bcm_gpio_softc *sc, uint32_t reg, uint32_t mask, + bool set_bits) +{ + + if (set_bits) + BCM_GPIO_SET_BITS(sc, reg, mask); + else + BCM_GPIO_CLEAR_BITS(sc, reg, mask); +} + +static inline void bcm_gpio_isrc_eoi(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi) { uint32_t bank; @@ -906,28 +925,64 @@ bcm_gpio_isrc_eoi(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi) static inline bool bcm_gpio_isrc_is_level(struct bcm_gpio_irqsrc *bgi) { - uint32_t bank; - bank = BCM_GPIO_BANK(bgi->bgi_irq); - return (bgi->bgi_reg == BCM_GPIO_GPHEN(bank) || - bgi->bgi_reg == BCM_GPIO_GPLEN(bank)); + return (bgi->bgi_mode == GPIO_INTR_LEVEL_LOW || + bgi->bgi_mode == GPIO_INTR_LEVEL_HIGH); } static inline void bcm_gpio_isrc_mask(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi) { + uint32_t bank; + bank = BCM_GPIO_BANK(bgi->bgi_irq); BCM_GPIO_LOCK(sc); - BCM_GPIO_CLEAR_BITS(sc, bgi->bgi_reg, bgi->bgi_mask); - BCM_GPIO_UNLOCK(bcm_gpio_sc); + switch (bgi->bgi_mode) { + case GPIO_INTR_LEVEL_LOW: + BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPLEN(bank), bgi->bgi_mask); + break; + case GPIO_INTR_LEVEL_HIGH: + BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPHEN(bank), bgi->bgi_mask); + break; + case GPIO_INTR_EDGE_RISING: + BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask); + break; + case GPIO_INTR_EDGE_FALLING: + BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask); + break; + case GPIO_INTR_EDGE_BOTH: + BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask); + BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask); + break; + } + BCM_GPIO_UNLOCK(sc); } static inline void bcm_gpio_isrc_unmask(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi) { + uint32_t bank; + bank = BCM_GPIO_BANK(bgi->bgi_irq); BCM_GPIO_LOCK(sc); - BCM_GPIO_SET_BITS(sc, bgi->bgi_reg, bgi->bgi_mask); + switch (bgi->bgi_mode) { + case GPIO_INTR_LEVEL_LOW: + BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPLEN(bank), bgi->bgi_mask); + break; + case GPIO_INTR_LEVEL_HIGH: + BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPHEN(bank), bgi->bgi_mask); + break; + case GPIO_INTR_EDGE_RISING: + BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask); + break; + case GPIO_INTR_EDGE_FALLING: + BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask); + break; + case GPIO_INTR_EDGE_BOTH: + BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask); + BCM_GPIO_SET_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask); + break; + } BCM_GPIO_UNLOCK(sc); } @@ -983,7 +1038,7 @@ bcm_gpio_pic_attach(struct bcm_gpio_softc *sc) for (irq = 0; irq < BCM_GPIO_PINS; irq++) { sc->sc_isrcs[irq].bgi_irq = irq; sc->sc_isrcs[irq].bgi_mask = BCM_GPIO_MASK(irq); - sc->sc_isrcs[irq].bgi_reg = 0; + sc->sc_isrcs[irq].bgi_mode = GPIO_INTR_CONFORM; error = intr_isrc_register(&sc->sc_isrcs[irq].bgi_isrc, sc->sc_dev, 0, "%s,%u", name, irq); @@ -1007,6 +1062,26 @@ bcm_gpio_pic_detach(struct bcm_gpio_softc *sc) } static void +bcm_gpio_pic_config_intr(struct bcm_gpio_softc *sc, struct bcm_gpio_irqsrc *bgi, + uint32_t mode) +{ + uint32_t bank; + + bank = BCM_GPIO_BANK(bgi->bgi_irq); + BCM_GPIO_LOCK(sc); + bcm_gpio_modify(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask, + mode == GPIO_INTR_EDGE_RISING || mode == GPIO_INTR_EDGE_BOTH); + bcm_gpio_modify(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask, + mode == GPIO_INTR_EDGE_FALLING || mode == GPIO_INTR_EDGE_BOTH); + bcm_gpio_modify(sc, BCM_GPIO_GPHEN(bank), bgi->bgi_mask, + mode == GPIO_INTR_LEVEL_HIGH); + bcm_gpio_modify(sc, BCM_GPIO_GPLEN(bank), bgi->bgi_mask, + mode == GPIO_INTR_LEVEL_LOW); + bgi->bgi_mode = mode; + BCM_GPIO_UNLOCK(sc); +} + +static void bcm_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct bcm_gpio_softc *sc = device_get_softc(dev); @@ -1026,11 +1101,11 @@ bcm_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) } static int -bcm_gpio_pic_map_fdt(struct bcm_gpio_softc *sc, u_int ncells, pcell_t *cells, - u_int *irqp, uint32_t *regp) +bcm_gpio_pic_map_fdt(struct bcm_gpio_softc *sc, struct intr_map_data_fdt *daf, + u_int *irqp, uint32_t *modep) { u_int irq; - uint32_t reg, bank; + uint32_t mode, bank; /* * The first cell is the interrupt number. @@ -1041,51 +1116,83 @@ bcm_gpio_pic_map_fdt(struct bcm_gpio_softc *sc, u_int ncells, pcell_t *cells, * 4 = active high level-sensitive. * 8 = active low level-sensitive. */ - if (ncells != 2) + if (daf->ncells != 2) return (EINVAL); - irq = cells[0]; + irq = daf->cells[0]; if (irq >= BCM_GPIO_PINS || bcm_gpio_pin_is_ro(sc, irq)) return (EINVAL); - /* - * All interrupt types could be set for an interrupt at one moment. - * At least, the combination of 'low-to-high' and 'high-to-low' edge - * triggered interrupt types can make a sense. However, no combo is - * supported now. - */ + /* Only reasonable modes are supported. */ bank = BCM_GPIO_BANK(irq); - if (cells[1] == 1) - reg = BCM_GPIO_GPREN(bank); - else if (cells[1] == 2) - reg = BCM_GPIO_GPFEN(bank); - else if (cells[1] == 4) - reg = BCM_GPIO_GPHEN(bank); - else if (cells[1] == 8) - reg = BCM_GPIO_GPLEN(bank); + if (daf->cells[1] == 1) + mode = GPIO_INTR_EDGE_RISING; + else if (daf->cells[1] == 2) + mode = GPIO_INTR_EDGE_FALLING; + else if (daf->cells[1] == 3) + mode = GPIO_INTR_EDGE_BOTH; + else if (daf->cells[1] == 4) + mode = GPIO_INTR_LEVEL_HIGH; + else if (daf->cells[1] == 8) + mode = GPIO_INTR_LEVEL_LOW; else return (EINVAL); *irqp = irq; - if (regp != NULL) - *regp = reg; + if (modep != NULL) + *modep = mode; + return (0); +} + +static int +bcm_gpio_pic_map_gpio(struct bcm_gpio_softc *sc, struct intr_map_data_gpio *dag, + u_int *irqp, uint32_t *modep) +{ + u_int irq; + uint32_t mode; + + irq = dag->gpio_pin_num; + if (irq >= BCM_GPIO_PINS || bcm_gpio_pin_is_ro(sc, irq)) + return (EINVAL); + + mode = dag->gpio_intr_mode; + if (mode != GPIO_INTR_LEVEL_LOW && mode != GPIO_INTR_LEVEL_HIGH && + mode != GPIO_INTR_EDGE_RISING && mode != GPIO_INTR_EDGE_FALLING && + mode != GPIO_INTR_EDGE_BOTH) + return (EINVAL); + + *irqp = irq; + if (modep != NULL) + *modep = mode; return (0); } static int +bcm_gpio_pic_map(struct bcm_gpio_softc *sc, struct intr_map_data *data, + u_int *irqp, uint32_t *modep) +{ + + switch (data->type) { + case INTR_MAP_DATA_FDT: + return (bcm_gpio_pic_map_fdt(sc, + (struct intr_map_data_fdt *)data, irqp, modep)); + case INTR_MAP_DATA_GPIO: + return (bcm_gpio_pic_map_gpio(sc, + (struct intr_map_data_gpio *)data, irqp, modep)); + default: + return (ENOTSUP); + } +} + +static int bcm_gpio_pic_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { int error; u_int irq; - struct bcm_gpio_softc *sc; - - if (data->type != INTR_MAP_DATA_FDT) - return (ENOTSUP); + struct bcm_gpio_softc *sc = device_get_softc(dev); - sc = device_get_softc(dev); - error = bcm_gpio_pic_map_fdt(sc, data->fdt.ncells, data->fdt.cells, - &irq, NULL); + error = bcm_gpio_pic_map(sc, data, &irq, NULL); if (error == 0) *isrcp = &sc->sc_isrcs[irq].bgi_isrc; return (error); @@ -1124,19 +1231,18 @@ bcm_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { u_int irq; - uint32_t bank, reg; + uint32_t mode; struct bcm_gpio_softc *sc; struct bcm_gpio_irqsrc *bgi; - if (data == NULL || data->type != INTR_MAP_DATA_FDT) + if (data == NULL) return (ENOTSUP); sc = device_get_softc(dev); bgi = (struct bcm_gpio_irqsrc *)isrc; /* Get and check config for an interrupt. */ - if (bcm_gpio_pic_map_fdt(sc, data->fdt.ncells, data->fdt.cells, &irq, - ®) != 0 || bgi->bgi_irq != irq) + if (bcm_gpio_pic_map(sc, data, &irq, &mode) != 0 || bgi->bgi_irq != irq) return (EINVAL); /* @@ -1144,17 +1250,9 @@ bcm_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, * only check that its configuration match. */ if (isrc->isrc_handlers != 0) - return (bgi->bgi_reg == reg ? 0 : EINVAL); + return (bgi->bgi_mode == mode ? 0 : EINVAL); - bank = BCM_GPIO_BANK(irq); - BCM_GPIO_LOCK(sc); - BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPREN(bank), bgi->bgi_mask); - BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPFEN(bank), bgi->bgi_mask); - BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPHEN(bank), bgi->bgi_mask); - BCM_GPIO_CLEAR_BITS(sc, BCM_GPIO_GPLEN(bank), bgi->bgi_mask); - bgi->bgi_reg = reg; - BCM_GPIO_SET_BITS(sc, reg, bgi->bgi_mask); - BCM_GPIO_UNLOCK(sc); + bcm_gpio_pic_config_intr(sc, bgi, mode); return (0); } @@ -1165,12 +1263,8 @@ bcm_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, struct bcm_gpio_softc *sc = device_get_softc(dev); struct bcm_gpio_irqsrc *bgi = (struct bcm_gpio_irqsrc *)isrc; - if (isrc->isrc_handlers == 0) { - BCM_GPIO_LOCK(sc); - BCM_GPIO_CLEAR_BITS(sc, bgi->bgi_reg, bgi->bgi_mask); - bgi->bgi_reg = 0; - BCM_GPIO_UNLOCK(sc); - } + if (isrc->isrc_handlers == 0) + bcm_gpio_pic_config_intr(sc, bgi, GPIO_INTR_CONFORM); return (0); } diff --git a/sys/arm/broadcom/bcm2835/bcm2835_intr.c b/sys/arm/broadcom/bcm2835/bcm2835_intr.c index 8124c96..39ad5f7 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_intr.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_intr.c @@ -268,14 +268,17 @@ bcm_intc_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { u_int irq; + struct intr_map_data_fdt *daf; struct bcm_intc_softc *sc; if (data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); - if (data->fdt.ncells == 1) - irq = data->fdt.cells[0]; - else if (data->fdt.ncells == 2) - irq = data->fdt.cells[0] * 32 + data->fdt.cells[1]; + + daf = (struct intr_map_data_fdt *)data; + if (daf->ncells == 1) + irq = daf->cells[0]; + else if (daf->ncells == 2) + irq = daf->cells[0] * 32 + daf->cells[1]; else return (EINVAL); diff --git a/sys/arm/broadcom/bcm2835/bcm2836.c b/sys/arm/broadcom/bcm2835/bcm2836.c index 16c1e4b..3991609 100644 --- a/sys/arm/broadcom/bcm2835/bcm2836.c +++ b/sys/arm/broadcom/bcm2835/bcm2836.c @@ -461,15 +461,18 @@ static int bcm_lintc_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { + struct intr_map_data_fdt *daf; struct bcm_lintc_softc *sc; if (data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); - if (data->fdt.ncells != 1 || data->fdt.cells[0] >= BCM_LINTC_NIRQS) + + daf = (struct intr_map_data_fdt *)data; + if (daf->ncells != 1 || daf->cells[0] >= BCM_LINTC_NIRQS) return (EINVAL); sc = device_get_softc(dev); - *isrcp = &sc->bls_isrcs[data->fdt.cells[0]].bli_isrc; + *isrcp = &sc->bls_isrcs[daf->cells[0]].bli_isrc; return (0); } diff --git a/sys/arm/cavium/cns11xx/if_ece.c b/sys/arm/cavium/cns11xx/if_ece.c index 2ae3d22..9ed5cbd 100644 --- a/sys/arm/cavium/cns11xx/if_ece.c +++ b/sys/arm/cavium/cns11xx/if_ece.c @@ -1685,7 +1685,7 @@ ece_encap(struct ece_softc *sc, struct mbuf *m0) /* * After all descriptors are set, we set the flags to start the - * sending proces. + * sending process. */ for (seg = 0; seg < nsegs; seg++) { desc->cown = 0; diff --git a/sys/arm/conf/ALLWINNER b/sys/arm/conf/ALLWINNER index 9bb0e0a..3d0acb5 100644 --- a/sys/arm/conf/ALLWINNER +++ b/sys/arm/conf/ALLWINNER @@ -28,6 +28,7 @@ options INTRNG options SOC_ALLWINNER_A20 options SOC_ALLWINNER_A31 options SOC_ALLWINNER_A31S +options SOC_ALLWINNER_A83T options HZ=100 options SCHED_ULE # ULE scheduler @@ -121,6 +122,7 @@ device bpf #device emac # 10/100 integrated EMAC controller device dwc # 10/100/1000 integrated GMAC controller +device awg # 10/100/1000 integrated EMAC controller # USB ethernet support, requires miibus device miibus diff --git a/sys/arm/freescale/imx/imx6_ipu.c b/sys/arm/freescale/imx/imx6_ipu.c index d1efbff..f561fa7 100644 --- a/sys/arm/freescale/imx/imx6_ipu.c +++ b/sys/arm/freescale/imx/imx6_ipu.c @@ -872,7 +872,7 @@ ipu_init_buffer(struct ipu_softc *sc) stride = sc->sc_mode->hdisplay * MODE_BPP / 8; - /* init channel paramters */ + /* init channel parameters */ CH_PARAM_RESET(¶m); /* XXX: interlaced modes are not supported yet */ CH_PARAM_SET_FW(¶m, sc->sc_mode->hdisplay - 1); diff --git a/sys/arm/freescale/imx/imx6_ssi.c b/sys/arm/freescale/imx/imx6_ssi.c index 9387aa3..9000ae3 100644 --- a/sys/arm/freescale/imx/imx6_ssi.c +++ b/sys/arm/freescale/imx/imx6_ssi.c @@ -738,7 +738,7 @@ ssi_attach(device_t dev) sc->lock = snd_mtxcreate(device_get_nameunit(dev), "ssi softc"); if (sc->lock == NULL) { - device_printf(dev, "Cant create mtx\n"); + device_printf(dev, "Can't create mtx\n"); return (ENXIO); } @@ -764,7 +764,7 @@ ssi_attach(device_t dev) /* * Maximum possible DMA buffer. - * Will be used partialy to match 24 bit word. + * Will be used partially to match 24 bit word. */ sc->dma_size = 131072; diff --git a/sys/arm/freescale/imx/imx_gpio.c b/sys/arm/freescale/imx/imx_gpio.c index ba82f5c..c5f7b8c 100644 --- a/sys/arm/freescale/imx/imx_gpio.c +++ b/sys/arm/freescale/imx/imx_gpio.c @@ -225,13 +225,15 @@ gpio_pic_map_intr(device_t dev, struct intr_map_data *data, { int error; u_int irq; + struct intr_map_data_fdt *daf; struct imx51_gpio_softc *sc; if (data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); - error = gpio_pic_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq, - NULL, NULL); + daf = (struct intr_map_data_fdt *)data; + error = gpio_pic_map_fdt(dev, daf->ncells, daf->cells, &irq, NULL, + NULL); if (error == 0) { sc = device_get_softc(dev); *isrcp = &sc->gpio_pic_irqsrc[irq].gi_isrc; @@ -265,6 +267,7 @@ static int gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { + struct intr_map_data_fdt *daf; struct imx51_gpio_softc *sc; struct gpio_irqsrc *gi; int error, icfg; @@ -278,8 +281,9 @@ gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, /* Get config for interrupt. */ if (data == NULL || data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); - error = gpio_pic_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq, - &pol, &trig); + daf = (struct intr_map_data_fdt *)data; + error = gpio_pic_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol, + &trig); if (error != 0) return (error); if (gi->gi_irq != irq) diff --git a/sys/arm/freescale/vybrid/vf_uart.c b/sys/arm/freescale/vybrid/vf_uart.c index 312f18c..61a08fb 100644 --- a/sys/arm/freescale/vybrid/vf_uart.c +++ b/sys/arm/freescale/vybrid/vf_uart.c @@ -205,7 +205,7 @@ uart_reinit(struct uart_softc *sc, int clkspeed, int baud) bas = &sc->sc_bas; if (!bas) { - printf("Error: cant reconfigure bas\n"); + printf("Error: can't reconfigure bas\n"); return; } diff --git a/sys/arm/mv/mpic.c b/sys/arm/mv/mpic.c index 4c5856a..7e07d66 100644 --- a/sys/arm/mv/mpic.c +++ b/sys/arm/mv/mpic.c @@ -339,15 +339,19 @@ static int mpic_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { + struct intr_map_data_fdt *daf; struct mv_mpic_softc *sc; + if (data->type != INTR_MAP_DATA_FDT) + return (ENOTSUP); + sc = device_get_softc(dev); + daf = (struct intr_map_data_fdt *)data; - if (data->type != INTR_MAP_DATA_FDT || data->fdt.ncells !=1 || - data->fdt.cells[0] >= sc->nirqs) + if (daf->ncells !=1 || daf->cells[0] >= sc->nirqs) return (EINVAL); - *isrcp = &sc->mpic_isrcs[data->fdt.cells[0]].mmi_isrc; + *isrcp = &sc->mpic_isrcs[daf->cells[0]].mmi_isrc; return (0); } @@ -564,7 +568,7 @@ mv_msi_data(int irq, uint64_t *addr, uint32_t *data) node = ofw_bus_get_node(mv_mpic_sc->sc_dev); - /* Get physical addres of register space */ + /* Get physical address of register space */ error = fdt_get_range(OF_parent(node), 0, &phys, &size); if (error) { printf("%s: Cannot get register physical address, err:%d", diff --git a/sys/arm/mv/mv_common.c b/sys/arm/mv/mv_common.c index 2bd13f6..55e3cd1 100644 --- a/sys/arm/mv/mv_common.c +++ b/sys/arm/mv/mv_common.c @@ -1398,7 +1398,7 @@ decode_win_pcie_setup(u_long base) /* * Upper 16 bits in BAR register is interpreted as BAR size - * (in 64 kB units) plus 64kB, so substract 0x10000 + * (in 64 kB units) plus 64kB, so subtract 0x10000 * form value passed to register to get correct value. */ size -= 0x10000; diff --git a/sys/arm/nvidia/tegra_gpio.c b/sys/arm/nvidia/tegra_gpio.c index 0b2b081..7329ce0 100644 --- a/sys/arm/nvidia/tegra_gpio.c +++ b/sys/arm/nvidia/tegra_gpio.c @@ -579,14 +579,19 @@ tegra_gpio_pic_map_intr(device_t dev, struct intr_map_data *data, sc = device_get_softc(dev); - if (data->type == INTR_MAP_DATA_FDT) - rv = tegra_gpio_pic_map_fdt(sc, data->fdt.ncells, - data->fdt.cells, &irq, NULL); - else if (data->type == INTR_MAP_DATA_GPIO) - rv = tegra_gpio_pic_map_gpio(sc, data->gpio.gpio_pin_num, - data->gpio.gpio_pin_flags, data->gpio.gpio_intr_mode, - &irq, NULL); - else + if (data->type == INTR_MAP_DATA_FDT) { + struct intr_map_data_fdt *daf; + + daf = (struct intr_map_data_fdt *)data; + rv = tegra_gpio_pic_map_fdt(sc, daf->ncells, daf->cells, &irq, + NULL); + } else if (data->type == INTR_MAP_DATA_GPIO) { + struct intr_map_data_gpio *dag; + + dag = (struct intr_map_data_gpio *)data; + rv = tegra_gpio_pic_map_gpio(sc, dag->gpio_pin_num, + dag->gpio_pin_flags, dag->gpio_intr_mode, &irq, NULL); + } else return (ENOTSUP); if (rv == 0) @@ -648,14 +653,19 @@ tegra_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, return (ENOTSUP); /* Get and check config for an interrupt. */ - if (data->type == INTR_MAP_DATA_FDT) - rv = tegra_gpio_pic_map_fdt(sc, data->fdt.ncells, - data->fdt.cells, &irq, &cfgreg); - else if (data->type == INTR_MAP_DATA_GPIO) - rv = tegra_gpio_pic_map_gpio(sc, data->gpio.gpio_pin_num, - data->gpio.gpio_pin_flags, data->gpio.gpio_intr_mode, - &irq, &cfgreg); - else + if (data->type == INTR_MAP_DATA_FDT) { + struct intr_map_data_fdt *daf; + + daf = (struct intr_map_data_fdt *)data; + rv = tegra_gpio_pic_map_fdt(sc, daf->ncells, daf->cells, &irq, + &cfgreg); + } else if (data->type == INTR_MAP_DATA_GPIO) { + struct intr_map_data_gpio *dag; + + dag = (struct intr_map_data_gpio *)data; + rv = tegra_gpio_pic_map_gpio(sc, dag->gpio_pin_num, + dag->gpio_pin_flags, dag->gpio_intr_mode, &irq, &cfgreg); + } else return (ENOTSUP); if (rv != 0) return (EINVAL); diff --git a/sys/arm/qemu/virt_machdep.c b/sys/arm/qemu/virt_machdep.c index 95cc225..d15b97c 100644 --- a/sys/arm/qemu/virt_machdep.c +++ b/sys/arm/qemu/virt_machdep.c @@ -97,3 +97,20 @@ static platform_method_t virt_methods[] = { }; FDT_PLATFORM_DEF(virt, "virt", 0, "linux,dummy-virt", 1); + +static int +gem5_devmap_init(platform_t plat) +{ + + devmap_add_entry(0x1c090000, 0x100000); /* Uart */ + return (0); +} + +static platform_method_t gem5_methods[] = { + PLATFORMMETHOD(platform_devmap_init, gem5_devmap_init), + PLATFORMMETHOD(platform_lastaddr, virt_lastaddr), + + PLATFORMMETHOD_END, +}; + +FDT_PLATFORM_DEF(gem5, "gem5", 0, "arm,vexpress", 1); diff --git a/sys/arm/samsung/exynos/exynos5_usb_phy.c b/sys/arm/samsung/exynos/exynos5_usb_phy.c index 2756efb..430c8f8 100644 --- a/sys/arm/samsung/exynos/exynos5_usb_phy.c +++ b/sys/arm/samsung/exynos/exynos5_usb_phy.c @@ -161,7 +161,7 @@ vbus_on(struct usb_phy_softc *sc) gpio_dev = devclass_get_device(devclass_find("gpio"), 0); if (gpio_dev == NULL) { - device_printf(sc->dev, "cant find gpio_dev\n"); + device_printf(sc->dev, "can't find gpio_dev\n"); return (1); } diff --git a/sys/arm/ti/aintc.c b/sys/arm/ti/aintc.c index ebe4864..5fb4695 100644 --- a/sys/arm/ti/aintc.c +++ b/sys/arm/ti/aintc.c @@ -178,14 +178,18 @@ static int ti_aintc_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { + struct intr_map_data_fdt *daf; struct ti_aintc_softc *sc; - if (data->type != INTR_MAP_DATA_FDT || data->fdt.ncells != 1 || - data->fdt.cells[0] >= INTC_NIRQS) + if (data->type != INTR_MAP_DATA_FDT) + return (ENOTSUP); + + daf = (struct intr_map_data_fdt *)data; + if (daf->ncells != 1 || daf->cells[0] >= INTC_NIRQS) return (EINVAL); sc = device_get_softc(dev); - *isrcp = &sc->aintc_isrcs[data->fdt.cells[0]].tai_isrc; + *isrcp = &sc->aintc_isrcs[daf->cells[0]].tai_isrc; return (0); } diff --git a/sys/arm/ti/omap4/omap4_prcm_clks.c b/sys/arm/ti/omap4/omap4_prcm_clks.c index e83e6ee..e17fe3d 100644 --- a/sys/arm/ti/omap4/omap4_prcm_clks.c +++ b/sys/arm/ti/omap4/omap4_prcm_clks.c @@ -1329,7 +1329,7 @@ omap4_clk_hsusbhost_accessible(struct ti_clock_dev *clkdev) * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: - * Returns 0 if sucessful otherwise a negative error code on failure. + * Returns 0 if successful otherwise a negative error code on failure. */ static int omap4_clk_hsusbhost_set_source(struct ti_clock_dev *clkdev, diff --git a/sys/arm/ti/ti_gpio.c b/sys/arm/ti/ti_gpio.c index 54e5042..a67884e 100644 --- a/sys/arm/ti/ti_gpio.c +++ b/sys/arm/ti/ti_gpio.c @@ -290,7 +290,7 @@ ti_gpio_valid_pin(struct ti_gpio_softc *sc, int pin) } /** - * ti_gpio_pin_getcaps - Gets the capabilties of a given pin + * ti_gpio_pin_getcaps - Gets the capabilities of a given pin * @dev: gpio device handle * @pin: the number of the pin * @caps: pointer to a value that upon return will contain the capabilities @@ -300,6 +300,11 @@ ti_gpio_valid_pin(struct ti_gpio_softc *sc, int pin) * - GPIO_PIN_OUTPUT * - GPIO_PIN_PULLUP * - GPIO_PIN_PULLDOWN + * - GPIO_INTR_LEVEL_LOW + * - GPIO_INTR_LEVEL_HIGH + * - GPIO_INTR_EDGE_RISING + * - GPIO_INTR_EDGE_FALLING + * - GPIO_INTR_EDGE_BOTH * * LOCKING: * No locking required, returns static data. @@ -316,8 +321,15 @@ ti_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); +#ifdef INTRNG + *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | + GPIO_PIN_PULLDOWN | GPIO_INTR_LEVEL_LOW | GPIO_INTR_LEVEL_HIGH | + GPIO_INTR_EDGE_RISING | GPIO_INTR_EDGE_FALLING | + GPIO_INTR_EDGE_BOTH); +#else *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN); +#endif return (0); } @@ -800,17 +812,13 @@ ti_gpio_detach(device_t dev) #ifdef INTRNG static inline void -ti_gpio_rwreg_set(struct ti_gpio_softc *sc, uint32_t reg, uint32_t mask) -{ - - ti_gpio_write_4(sc, reg, ti_gpio_read_4(sc, reg) | mask); -} - -static inline void -ti_gpio_rwreg_clr(struct ti_gpio_softc *sc, uint32_t reg, uint32_t mask) +ti_gpio_rwreg_modify(struct ti_gpio_softc *sc, uint32_t reg, uint32_t mask, + bool set_bits) { + uint32_t value; - ti_gpio_write_4(sc, reg, ti_gpio_read_4(sc, reg) & ~mask); + value = ti_gpio_read_4(sc, reg); + ti_gpio_write_4(sc, reg, set_bits ? value | mask : value & ~mask); } static inline void @@ -841,8 +849,8 @@ static inline bool ti_gpio_isrc_is_level(struct ti_gpio_irqsrc *tgi) { - return (tgi->tgi_cfgreg == TI_GPIO_LEVELDETECT0 || - tgi->tgi_cfgreg == TI_GPIO_LEVELDETECT1); + return (tgi->tgi_mode == GPIO_INTR_LEVEL_LOW || + tgi->tgi_mode == GPIO_INTR_LEVEL_HIGH); } static int @@ -889,7 +897,7 @@ ti_gpio_pic_attach(struct ti_gpio_softc *sc) for (irq = 0; irq < sc->sc_maxpin; irq++) { sc->sc_isrcs[irq].tgi_irq = irq; sc->sc_isrcs[irq].tgi_mask = TI_GPIO_MASK(irq); - sc->sc_isrcs[irq].tgi_cfgreg = 0; + sc->sc_isrcs[irq].tgi_mode = GPIO_INTR_CONFORM; error = intr_isrc_register(&sc->sc_isrcs[irq].tgi_isrc, sc->sc_dev, 0, "%s,%u", name, irq); @@ -913,6 +921,24 @@ ti_gpio_pic_detach(struct ti_gpio_softc *sc) } static void +ti_gpio_pic_config_intr(struct ti_gpio_softc *sc, struct ti_gpio_irqsrc *tgi, + uint32_t mode) +{ + + TI_GPIO_LOCK(sc); + ti_gpio_rwreg_modify(sc, TI_GPIO_RISINGDETECT, tgi->tgi_mask, + mode == GPIO_INTR_EDGE_RISING || mode == GPIO_INTR_EDGE_BOTH); + ti_gpio_rwreg_modify(sc, TI_GPIO_FALLINGDETECT, tgi->tgi_mask, + mode == GPIO_INTR_EDGE_FALLING || mode == GPIO_INTR_EDGE_BOTH); + ti_gpio_rwreg_modify(sc, TI_GPIO_LEVELDETECT1, tgi->tgi_mask, + mode == GPIO_INTR_LEVEL_HIGH); + ti_gpio_rwreg_modify(sc, TI_GPIO_LEVELDETECT0, tgi->tgi_mask, + mode == GPIO_INTR_LEVEL_LOW); + tgi->tgi_mode = mode; + TI_GPIO_UNLOCK(sc); +} + +static void ti_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct ti_gpio_softc *sc = device_get_softc(dev); @@ -932,10 +958,10 @@ ti_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) } static int -ti_gpio_pic_map_fdt(struct ti_gpio_softc *sc, u_int ncells, pcell_t *cells, - u_int *irqp, uint32_t *regp) +ti_gpio_pic_map_fdt(struct ti_gpio_softc *sc, struct intr_map_data_fdt *daf, + u_int *irqp, uint32_t *modep) { - uint32_t reg; + uint32_t mode; /* * The first cell is the interrupt number. @@ -946,46 +972,76 @@ ti_gpio_pic_map_fdt(struct ti_gpio_softc *sc, u_int ncells, pcell_t *cells, * 4 = active high level-sensitive. * 8 = active low level-sensitive. */ - if (ncells != 2 || cells[0] >= sc->sc_maxpin) + if (daf->ncells != 2 || daf->cells[0] >= sc->sc_maxpin) return (EINVAL); - /* - * All interrupt types could be set for an interrupt at one moment. - * At least, the combination of 'low-to-high' and 'high-to-low' edge - * triggered interrupt types can make a sense. However, no combo is - * supported now. - */ - if (cells[1] == 1) - reg = TI_GPIO_RISINGDETECT; - else if (cells[1] == 2) - reg = TI_GPIO_FALLINGDETECT; - else if (cells[1] == 4) - reg = TI_GPIO_LEVELDETECT1; - else if (cells[1] == 8) - reg = TI_GPIO_LEVELDETECT0; + /* Only reasonable modes are supported. */ + if (daf->cells[1] == 1) + mode = GPIO_INTR_EDGE_RISING; + else if (daf->cells[1] == 2) + mode = GPIO_INTR_EDGE_FALLING; + else if (daf->cells[1] == 3) + mode = GPIO_INTR_EDGE_BOTH; + else if (daf->cells[1] == 4) + mode = GPIO_INTR_LEVEL_HIGH; + else if (daf->cells[1] == 8) + mode = GPIO_INTR_LEVEL_LOW; else return (EINVAL); - *irqp = cells[0]; - if (regp != NULL) - *regp = reg; + *irqp = daf->cells[0]; + if (modep != NULL) + *modep = mode; return (0); } static int +ti_gpio_pic_map_gpio(struct ti_gpio_softc *sc, struct intr_map_data_gpio *dag, + u_int *irqp, uint32_t *modep) +{ + uint32_t mode; + + if (dag->gpio_pin_num >= sc->sc_maxpin) + return (EINVAL); + + mode = dag->gpio_intr_mode; + if (mode != GPIO_INTR_LEVEL_LOW && mode != GPIO_INTR_LEVEL_HIGH && + mode != GPIO_INTR_EDGE_RISING && mode != GPIO_INTR_EDGE_FALLING && + mode != GPIO_INTR_EDGE_BOTH) + return (EINVAL); + + *irqp = dag->gpio_pin_num; + if (modep != NULL) + *modep = mode; + return (0); +} + +static int +ti_gpio_pic_map(struct ti_gpio_softc *sc, struct intr_map_data *data, + u_int *irqp, uint32_t *modep) +{ + + switch (data->type) { + case INTR_MAP_DATA_FDT: + return (ti_gpio_pic_map_fdt(sc, + (struct intr_map_data_fdt *)data, irqp, modep)); + case INTR_MAP_DATA_GPIO: + return (ti_gpio_pic_map_gpio(sc, + (struct intr_map_data_gpio *)data, irqp, modep)); + default: + return (ENOTSUP); + } +} + +static int ti_gpio_pic_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { int error; u_int irq; - struct ti_gpio_softc *sc; - - if (data->type != INTR_MAP_DATA_FDT) - return (ENOTSUP); + struct ti_gpio_softc *sc = device_get_softc(dev); - sc = device_get_softc(dev); - error = ti_gpio_pic_map_fdt(sc, data->fdt.ncells, data->fdt.cells, &irq, - NULL); + error = ti_gpio_pic_map(sc, data, &irq, NULL); if (error == 0) *isrcp = &sc->sc_isrcs[irq].tgi_isrc; return (error); @@ -1024,19 +1080,18 @@ ti_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { u_int irq; - uint32_t cfgreg; + uint32_t mode; struct ti_gpio_softc *sc; struct ti_gpio_irqsrc *tgi; - if (data == NULL || data->type != INTR_MAP_DATA_FDT) + if (data == NULL) return (ENOTSUP); sc = device_get_softc(dev); tgi = (struct ti_gpio_irqsrc *)isrc; /* Get and check config for an interrupt. */ - if (ti_gpio_pic_map_fdt(sc, data->fdt.ncells, data->fdt.cells, &irq, - &cfgreg) != 0 || tgi->tgi_irq != irq) + if (ti_gpio_pic_map(sc, data, &irq, &mode) != 0 || tgi->tgi_irq != irq) return (EINVAL); /* @@ -1044,16 +1099,9 @@ ti_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, * only check that its configuration match. */ if (isrc->isrc_handlers != 0) - return (tgi->tgi_cfgreg == cfgreg ? 0 : EINVAL); + return (tgi->tgi_mode == mode ? 0 : EINVAL); - TI_GPIO_LOCK(sc); - ti_gpio_rwreg_clr(sc, TI_GPIO_RISINGDETECT, tgi->tgi_mask); - ti_gpio_rwreg_clr(sc, TI_GPIO_FALLINGDETECT, tgi->tgi_mask); - ti_gpio_rwreg_clr(sc, TI_GPIO_LEVELDETECT1, tgi->tgi_mask); - ti_gpio_rwreg_clr(sc, TI_GPIO_LEVELDETECT0, tgi->tgi_mask); - tgi->tgi_cfgreg = cfgreg; - ti_gpio_rwreg_set(sc, cfgreg, tgi->tgi_mask); - TI_GPIO_UNLOCK(sc); + ti_gpio_pic_config_intr(sc, tgi, mode); return (0); } @@ -1064,12 +1112,8 @@ ti_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, struct ti_gpio_softc *sc = device_get_softc(dev); struct ti_gpio_irqsrc *tgi = (struct ti_gpio_irqsrc *)isrc; - if (isrc->isrc_handlers == 0) { - TI_GPIO_LOCK(sc); - ti_gpio_rwreg_clr(sc, tgi->tgi_cfgreg, tgi->tgi_mask); - tgi->tgi_cfgreg = 0; - TI_GPIO_UNLOCK(sc); - } + if (isrc->isrc_handlers == 0) + ti_gpio_pic_config_intr(sc, tgi, GPIO_INTR_CONFORM); return (0); } diff --git a/sys/arm/ti/ti_gpio.h b/sys/arm/ti/ti_gpio.h index 174dd62..c9785dd 100644 --- a/sys/arm/ti/ti_gpio.h +++ b/sys/arm/ti/ti_gpio.h @@ -49,7 +49,7 @@ struct ti_gpio_irqsrc { struct intr_irqsrc tgi_isrc; u_int tgi_irq; uint32_t tgi_mask; - uint32_t tgi_cfgreg; + uint32_t tgi_mode; }; #endif diff --git a/sys/arm/ti/ti_i2c.c b/sys/arm/ti/ti_i2c.c index 92a44a7..55336ff 100644 --- a/sys/arm/ti/ti_i2c.c +++ b/sys/arm/ti/ti_i2c.c @@ -236,7 +236,7 @@ ti_i2c_transfer_intr(struct ti_i2c_softc* sc, uint16_t status) if (status & I2C_STAT_RDR) { /* * Receive draining interrupt - last data received. - * The set FIFO threshold wont be reached to trigger + * The set FIFO threshold won't be reached to trigger * RRDY. */ ti_i2c_dbg(sc, "Receive draining interrupt\n"); @@ -272,7 +272,7 @@ ti_i2c_transfer_intr(struct ti_i2c_softc* sc, uint16_t status) /* * Transmit draining interrupt - FIFO level is below * the set threshold and the amount of data still to - * be transferred wont reach the set FIFO threshold. + * be transferred won't reach the set FIFO threshold. */ ti_i2c_dbg(sc, "Transmit draining interrupt\n"); diff --git a/sys/arm/ti/ti_pinmux.c b/sys/arm/ti/ti_pinmux.c index ff4743d..ffeaf75 100644 --- a/sys/arm/ti/ti_pinmux.c +++ b/sys/arm/ti/ti_pinmux.c @@ -394,7 +394,7 @@ ti_pinmux_probe(device_t dev) * @dev: new device * * RETURNS - * Zero on sucess or ENXIO if an error occuried. + * Zero on success or ENXIO if an error occuried. */ static int ti_pinmux_attach(device_t dev) diff --git a/sys/arm/ti/ti_prcm.c b/sys/arm/ti/ti_prcm.c index c5ab9c7..d742d07 100644 --- a/sys/arm/ti/ti_prcm.c +++ b/sys/arm/ti/ti_prcm.c @@ -31,7 +31,7 @@ */ /** - * Power, Reset and Clock Managment Module + * Power, Reset and Clock Management Module * * This is a very simple driver wrapper around the PRCM set of registers in * the OMAP3 chip. It allows you to turn on and off things like the functional diff --git a/sys/arm/ti/ti_scm.c b/sys/arm/ti/ti_scm.c index 14e9200..5608265 100644 --- a/sys/arm/ti/ti_scm.c +++ b/sys/arm/ti/ti_scm.c @@ -111,7 +111,7 @@ ti_scm_probe(device_t dev) * globally and registers both the timecount and eventtimer objects. * * RETURNS - * Zero on sucess or ENXIO if an error occuried. + * Zero on success or ENXIO if an error occuried. */ static int ti_scm_attach(device_t dev) diff --git a/sys/arm/ti/ti_sdma.c b/sys/arm/ti/ti_sdma.c index a8faba8..7e5e957 100644 --- a/sys/arm/ti/ti_sdma.c +++ b/sys/arm/ti/ti_sdma.c @@ -446,7 +446,7 @@ ti_sdma_deactivate_channel(unsigned int ch) * ti_sdma_disable_channel_irq - disables IRQ's on the given channel * @ch: the channel to disable IRQ's on * - * Disable interupt generation for the given channel. + * Disable interrupt generation for the given channel. * * LOCKING: * DMA registers protected by internal mutex @@ -608,7 +608,7 @@ ti_sdma_get_channel_status(unsigned int ch, uint32_t *status) /** * ti_sdma_start_xfer - starts a DMA transfer - * @ch: the channel number to set the endianess of + * @ch: the channel number to set the endianness of * @src_paddr: the source phsyical address * @dst_paddr: the destination phsyical address * @frmcnt: the number of frames per block @@ -707,7 +707,7 @@ ti_sdma_start_xfer(unsigned int ch, unsigned int src_paddr, * frmcnt = 1, elmcnt = 512, pktsize = 128 * * Total transfer bytes = 1 * 512 = 512 elements or 2048 bytes - * Packets transfered = 128 / 512 = 4 + * Packets transferred = 128 / 512 = 4 * * * LOCKING: @@ -787,7 +787,7 @@ ti_sdma_start_xfer_packet(unsigned int ch, unsigned int src_paddr, /** * ti_sdma_stop_xfer - stops any currently active transfers - * @ch: the channel number to set the endianess of + * @ch: the channel number to set the endianness of * * This function call is effectively a NOP if no transaction is in progress. * @@ -835,10 +835,10 @@ ti_sdma_stop_xfer(unsigned int ch) } /** - * ti_sdma_set_xfer_endianess - sets the endianess of subsequent transfers - * @ch: the channel number to set the endianess of - * @src: the source endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG) - * @dst: the destination endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG) + * ti_sdma_set_xfer_endianess - sets the endianness of subsequent transfers + * @ch: the channel number to set the endianness of + * @src: the source endianness (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG) + * @dst: the destination endianness (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG) * * * LOCKING: @@ -879,9 +879,9 @@ ti_sdma_set_xfer_endianess(unsigned int ch, unsigned int src, unsigned int dst) /** * ti_sdma_set_xfer_burst - sets the source and destination element size * @ch: the channel number to set the burst settings of - * @src: the source endianess (either DMA_BURST_NONE, DMA_BURST_16, DMA_BURST_32 + * @src: the source endianness (either DMA_BURST_NONE, DMA_BURST_16, DMA_BURST_32 * or DMA_BURST_64) - * @dst: the destination endianess (either DMA_BURST_NONE, DMA_BURST_16, + * @dst: the destination endianness (either DMA_BURST_NONE, DMA_BURST_16, * DMA_BURST_32 or DMA_BURST_64) * * This function sets the size of the elements for all subsequent transfers. @@ -923,7 +923,7 @@ ti_sdma_set_xfer_burst(unsigned int ch, unsigned int src, unsigned int dst) /** * ti_sdma_set_xfer_data_type - driver attach function - * @ch: the channel number to set the endianess of + * @ch: the channel number to set the endianness of * @type: the xfer data type (either DMA_DATA_8BITS_SCALAR, DMA_DATA_16BITS_SCALAR * or DMA_DATA_32BITS_SCALAR) * @@ -1065,7 +1065,7 @@ ti_sdma_sync_params(unsigned int ch, unsigned int trigger, unsigned int mode) /** * ti_sdma_set_addr_mode - driver attach function - * @ch: the channel number to set the endianess of + * @ch: the channel number to set the endianness of * @rd_mode: the xfer source addressing mode (either DMA_ADDR_CONSTANT, * DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or * DMA_ADDR_DOUBLE_INDEX) diff --git a/sys/arm/xilinx/zy7_slcr.c b/sys/arm/xilinx/zy7_slcr.c index e243ff6..c99d5b0 100644 --- a/sys/arm/xilinx/zy7_slcr.c +++ b/sys/arm/xilinx/zy7_slcr.c @@ -177,7 +177,7 @@ zy7_slcr_preload_pl(void) /* After PL configuration, enable level shifters and deassert top-level * PL resets. Called from zy7_devcfg.c. Optionally, the level shifters * can be left disabled but that's rare of an FPGA application. That option - * is controled by a sysctl in the devcfg driver. + * is controlled by a sysctl in the devcfg driver. */ void zy7_slcr_postload_pl(int en_level_shifters) diff --git a/sys/arm/xscale/i8134x/crb_machdep.c b/sys/arm/xscale/i8134x/crb_machdep.c index 5268ca9..898bbaa 100644 --- a/sys/arm/xscale/i8134x/crb_machdep.c +++ b/sys/arm/xscale/i8134x/crb_machdep.c @@ -38,7 +38,7 @@ * * machdep.c * - * Machine dependant functions for kernel setup + * Machine dependent functions for kernel setup * * This file needs a lot of work. * diff --git a/sys/arm/xscale/i8134x/i81342reg.h b/sys/arm/xscale/i8134x/i81342reg.h index fd087ce..2402194 100644 --- a/sys/arm/xscale/i8134x/i81342reg.h +++ b/sys/arm/xscale/i8134x/i81342reg.h @@ -184,7 +184,7 @@ #define ATU_IATVR2 0x005c /* Inbound ATU Translate Value Register 2 */ #define ATU_IAUTVR2 0x0060 /* Inbound ATU Upper Translate Value Register 2*/ #define ATU_ERLR 0x0064 /* Expansion ROM Limit Register */ -#define ATU_ERTVR 0x0068 /* Expansion ROM Translater Value Register */ +#define ATU_ERTVR 0x0068 /* Expansion ROM Translator Value Register */ #define ATU_ERUTVR 0x006c /* Expansion ROM Upper Translate Value Register*/ #define ATU_CR 0x0070 /* ATU Configuration Register */ #define ATU_CR_OUT_EN (1 << 1) diff --git a/sys/arm/xscale/ixp425/avila_machdep.c b/sys/arm/xscale/ixp425/avila_machdep.c index 46e4b10..f26d3ca 100644 --- a/sys/arm/xscale/ixp425/avila_machdep.c +++ b/sys/arm/xscale/ixp425/avila_machdep.c @@ -38,7 +38,7 @@ * * machdep.c * - * Machine dependant functions for kernel setup + * Machine dependent functions for kernel setup * * This file needs a lot of work. * diff --git a/sys/arm/xscale/ixp425/cambria_gpio.c b/sys/arm/xscale/ixp425/cambria_gpio.c index aa3947b..c871418 100644 --- a/sys/arm/xscale/ixp425/cambria_gpio.c +++ b/sys/arm/xscale/ixp425/cambria_gpio.c @@ -32,7 +32,7 @@ * The Cambria PLD does not set the i2c ack bit after each write, if we used the * regular iicbus interface it would abort the xfer after the address byte * times out and not write our latch. To get around this we grab the iicbus and - * then do our own bit banging. This is a comprimise to changing all the iicbb + * then do our own bit banging. This is a compromise to changing all the iicbb * device methods to allow a flag to be passed down and is similir to how Linux * does it. * diff --git a/sys/arm/xscale/ixp425/ixp425_npe.c b/sys/arm/xscale/ixp425/ixp425_npe.c index 6dbce4c..95facb4 100644 --- a/sys/arm/xscale/ixp425/ixp425_npe.c +++ b/sys/arm/xscale/ixp425/ixp425_npe.c @@ -507,7 +507,7 @@ ixpnpe_load_firmware(struct ixpnpe_softc *sc, const char *imageName, /* * If download was successful, store image Id in list of - * currently loaded images. If a critical error occured + * currently loaded images. If a critical error occurred * during download, record that the NPE has an invalid image */ mtx_lock(&sc->sc_mtx); @@ -864,7 +864,7 @@ npe_cpu_reset(struct ixpnpe_softc *sc) while (npe_checkbits(sc, IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_IFNE)) { /* - * Step execution of the NPE intruction to read inFIFO using + * Step execution of the NPE instruction to read inFIFO using * the Debug Executing Context stack. */ error = npe_cpu_step(sc, IX_NPEDL_INSTR_RD_FIFO, 0, 0); @@ -1307,7 +1307,7 @@ npe_logical_reg_write(struct ixpnpe_softc *sc, uint32_t regAddr, uint32_t regVal ((regVal & IX_NPEDL_MASK_IMMED_INSTR_COPROC_DATA) << IX_NPEDL_DISPLACE_IMMED_INSTR_COPROC_DATA); - /* step execution of NPE intruction using Debug ECS */ + /* step execution of NPE instruction using Debug ECS */ error = npe_cpu_step(sc, npeInstruction, ctxtNum, IX_NPEDL_WR_INSTR_LDUR); } diff --git a/sys/arm/xscale/ixp425/ixp425_npereg.h b/sys/arm/xscale/ixp425/ixp425_npereg.h index 069e9d7..94aff85 100644 --- a/sys/arm/xscale/ixp425/ixp425_npereg.h +++ b/sys/arm/xscale/ixp425/ixp425_npereg.h @@ -125,7 +125,7 @@ /* * Reset value for Mailbox (MBST) register - * NOTE that if used, it should be complemented with an NPE intruction + * NOTE that if used, it should be complemented with an NPE instruction * to clear the Mailbox at the NPE side as well */ #define IX_NPEDL_REG_RESET_MBST 0x0000F0F0 diff --git a/sys/arm/xscale/ixp425/ixp425_qmgr.c b/sys/arm/xscale/ixp425/ixp425_qmgr.c index 822623c..d6db260 100644 --- a/sys/arm/xscale/ixp425/ixp425_qmgr.c +++ b/sys/arm/xscale/ixp425/ixp425_qmgr.c @@ -421,7 +421,7 @@ ixpqmgr_qwrite(int qId, uint32_t entry) return ENOSPC; } /* - * No overflow occured : someone is draining the queue + * No overflow occurred : someone is draining the queue * and the current counter needs to be * updated from the current number of entries in the queue */ diff --git a/sys/arm/xscale/pxa/pxa_machdep.c b/sys/arm/xscale/pxa/pxa_machdep.c index 32cbcd8..bc3ab6f 100644 --- a/sys/arm/xscale/pxa/pxa_machdep.c +++ b/sys/arm/xscale/pxa/pxa_machdep.c @@ -38,7 +38,7 @@ * * machdep.c * - * Machine dependant functions for kernel setup + * Machine dependent functions for kernel setup * * This file needs a lot of work. * |