From owner-svn-src-all@FreeBSD.ORG Fri May 16 23:27:20 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id CF42E270; Fri, 16 May 2014 23:27:20 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id B80172417; Fri, 16 May 2014 23:27:20 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s4GNRKKt096245; Fri, 16 May 2014 23:27:20 GMT (envelope-from ian@svn.freebsd.org) Received: (from ian@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s4GNRIsh096230; Fri, 16 May 2014 23:27:18 GMT (envelope-from ian@svn.freebsd.org) Message-Id: <201405162327.s4GNRIsh096230@svn.freebsd.org> From: Ian Lepore Date: Fri, 16 May 2014 23:27:18 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r266274 - in stable/10: sbin/newfs_nandfs sys/arm/allwinner sys/arm/allwinner/a20 sys/arm/arm sys/arm/conf sys/arm/freescale/imx sys/arm/freescale/vybrid sys/arm/ti/omap4 sys/boot/fdt/d... X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 16 May 2014 23:27:20 -0000 Author: ian Date: Fri May 16 23:27:18 2014 New Revision: 266274 URL: http://svnweb.freebsd.org/changeset/base/266274 Log: MFC 262695, 262708, 262709, 262710, 262711, 262728, 262870, 262877, 262880, 262885, 262891, 262903, imx6: Add a tunable to set the number of active cores, enable SMP by default. ffec: Fix multicast filtering. Allwinner a10/a20... - Add gpio and clock bits for A10/A20's EMAC ethernet controller driver - EMAC gpio configuration - EMAC clock activation - Add Static Random Access Memory controller driver for A10/A20. A10/A20's SRAM is used by devices, such as CPU, EMAC, for extra fast memory or as cache. - Add EMAC 10/100 Ethernet controller driver for A10/A20. It is available mostly in A10 devices like Hackberry, Marsboard, Mele A1000, A2000, A100 HTPC, cubieboard1 and A20 device like cubieboard2. TX performance can be improved using both channels 0 and 1. RX performance is poor and needs improvement with the assistance of external DMA controller in case there - Add EMAC and SRAM controller entries to FDT. - Add EMAC device to kernel config files and enable EMAC, SRAM drivers. OMAP: When calculating the MPU freq, make sure not to overflow. Vybrid: - Add driver for Port control and interrupts (PORT). - Export panel info to DTS - Reset all the layers before setup first one - Enable display nandfs: Slight code reordering to make error branch last. Add option TMPFS to arm/conf/DEFAULTS, remove it from the few configs that have it individually. Concensus on freebsd-arm@ is that it should be included in all ARM kernels. Fix the arm sys_sigreturn(): its argument is a struct ucontext, not a struct sigframe containing the struct ucontext. Added: stable/10/sys/arm/allwinner/a10_gpio.h - copied unchanged from r262708, head/sys/arm/allwinner/a10_gpio.h stable/10/sys/arm/allwinner/a10_sramc.c - copied unchanged from r262709, head/sys/arm/allwinner/a10_sramc.c stable/10/sys/arm/allwinner/a10_sramc.h - copied unchanged from r262709, head/sys/arm/allwinner/a10_sramc.h stable/10/sys/arm/allwinner/if_emac.c - copied unchanged from r262710, head/sys/arm/allwinner/if_emac.c stable/10/sys/arm/allwinner/if_emacreg.h - copied unchanged from r262710, head/sys/arm/allwinner/if_emacreg.h stable/10/sys/arm/freescale/vybrid/vf_port.c - copied unchanged from r262885, head/sys/arm/freescale/vybrid/vf_port.c stable/10/sys/arm/freescale/vybrid/vf_port.h - copied unchanged from r262885, head/sys/arm/freescale/vybrid/vf_port.h Modified: stable/10/sbin/newfs_nandfs/newfs_nandfs.c stable/10/sys/arm/allwinner/a10_clk.c stable/10/sys/arm/allwinner/a10_clk.h stable/10/sys/arm/allwinner/a10_gpio.c stable/10/sys/arm/allwinner/a20/files.a20 stable/10/sys/arm/allwinner/files.a10 stable/10/sys/arm/arm/genassym.c stable/10/sys/arm/arm/locore.S stable/10/sys/arm/arm/machdep.c stable/10/sys/arm/conf/ARNDALE stable/10/sys/arm/conf/BEAGLEBONE stable/10/sys/arm/conf/CUBIEBOARD stable/10/sys/arm/conf/CUBIEBOARD2 stable/10/sys/arm/conf/DEFAULTS stable/10/sys/arm/conf/DIGI-CCWMX53 stable/10/sys/arm/conf/DOCKSTAR stable/10/sys/arm/conf/DREAMPLUG-1001 stable/10/sys/arm/conf/EFIKA_MX stable/10/sys/arm/conf/IMX53-QSB stable/10/sys/arm/conf/IMX6 stable/10/sys/arm/conf/VYBRID.common stable/10/sys/arm/conf/WANDBOARD.common stable/10/sys/arm/freescale/imx/imx6_mp.c stable/10/sys/arm/freescale/vybrid/files.vybrid stable/10/sys/arm/freescale/vybrid/vf_dcu4.c stable/10/sys/arm/freescale/vybrid/vf_gpio.c stable/10/sys/arm/ti/omap4/omap4_prcm_clks.c stable/10/sys/boot/fdt/dts/arm/cubieboard.dts stable/10/sys/boot/fdt/dts/arm/cubieboard2.dts stable/10/sys/boot/fdt/dts/arm/vybrid-quartz.dts stable/10/sys/boot/fdt/dts/arm/vybrid.dtsi stable/10/sys/dev/ffec/if_ffec.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sbin/newfs_nandfs/newfs_nandfs.c ============================================================================== --- stable/10/sbin/newfs_nandfs/newfs_nandfs.c Fri May 16 22:55:01 2014 (r266273) +++ stable/10/sbin/newfs_nandfs/newfs_nandfs.c Fri May 16 23:27:18 2014 (r266274) @@ -988,10 +988,10 @@ calculate_geometry(int fd) /* Get storage erase unit size */ if (!is_nand) erasesize = NANDFS_DEF_ERASESIZE; - else if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1) - errx(1, "Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); - else + else if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) != -1) erasesize = chip_params.page_size * chip_params.pages_per_block; + else + errx(1, "Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); debug("erasesize: %#jx", (uintmax_t)erasesize); Modified: stable/10/sys/arm/allwinner/a10_clk.c ============================================================================== --- stable/10/sys/arm/allwinner/a10_clk.c Fri May 16 22:55:01 2014 (r266273) +++ stable/10/sys/arm/allwinner/a10_clk.c Fri May 16 23:27:18 2014 (r266274) @@ -127,7 +127,7 @@ a10_clk_usb_activate(void) uint32_t reg_value; if (sc == NULL) - return ENXIO; + return (ENXIO); /* Gating AHB clock for USB */ reg_value = ccm_read_4(sc, CCM_AHB_GATING0); @@ -154,7 +154,7 @@ a10_clk_usb_deactivate(void) uint32_t reg_value; if (sc == NULL) - return ENXIO; + return (ENXIO); /* Disable clock for USB */ reg_value = ccm_read_4(sc, CCM_USB_CLK); @@ -173,3 +173,19 @@ a10_clk_usb_deactivate(void) return (0); } +int +a10_clk_emac_activate(void) { + struct a10_ccm_softc *sc = a10_ccm_sc; + uint32_t reg_value; + + if (sc == NULL) + return (ENXIO); + + /* Gating AHB clock for EMAC */ + reg_value = ccm_read_4(sc, CCM_AHB_GATING0); + reg_value |= CCM_AHB_GATING_EMAC; + ccm_write_4(sc, CCM_AHB_GATING0, reg_value); + + return (0); +} + Modified: stable/10/sys/arm/allwinner/a10_clk.h ============================================================================== --- stable/10/sys/arm/allwinner/a10_clk.h Fri May 16 22:55:01 2014 (r266273) +++ stable/10/sys/arm/allwinner/a10_clk.h Fri May 16 23:27:18 2014 (r266274) @@ -103,6 +103,7 @@ #define CCM_AHB_GATING_USB0 (1 << 0) #define CCM_AHB_GATING_EHCI0 (1 << 1) #define CCM_AHB_GATING_EHCI1 (1 << 3) +#define CCM_AHB_GATING_EMAC (1 << 17) #define CCM_USB_PHY (1 << 8) #define CCM_USB0_RESET (1 << 0) @@ -111,5 +112,6 @@ int a10_clk_usb_activate(void); int a10_clk_usb_deactivate(void); +int a10_clk_emac_activate(void); #endif /* _A10_CLK_H_ */ Modified: stable/10/sys/arm/allwinner/a10_gpio.c ============================================================================== --- stable/10/sys/arm/allwinner/a10_gpio.c Fri May 16 22:55:01 2014 (r266273) +++ stable/10/sys/arm/allwinner/a10_gpio.c Fri May 16 23:27:18 2014 (r266274) @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include #include "gpio_if.h" +#include "a10_gpio.h" /* * A10 have 9 banks of gpio. @@ -102,6 +103,8 @@ struct a10_gpio_softc { #define A10_GPIO_GP_INT_STA 0x214 #define A10_GPIO_GP_INT_DEB 0x218 +static struct a10_gpio_softc *a10_gpio_sc; + #define A10_GPIO_WRITE(_sc, _off, _val) \ bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val) #define A10_GPIO_READ(_sc, _off) \ @@ -473,6 +476,9 @@ a10_gpio_attach(device_t dev) device_add_child(dev, "gpioc", device_get_unit(dev)); device_add_child(dev, "gpiobus", device_get_unit(dev)); + + a10_gpio_sc = sc; + return (bus_generic_attach(dev)); fail: @@ -518,3 +524,19 @@ static driver_t a10_gpio_driver = { }; DRIVER_MODULE(a10_gpio, simplebus, a10_gpio_driver, a10_gpio_devclass, 0, 0); + +int +a10_emac_gpio_config(uint32_t pin) +{ + struct a10_gpio_softc *sc = a10_gpio_sc; + + if (sc == NULL) + return (ENXIO); + + /* Configure pin mux settings for MII. */ + A10_GPIO_LOCK(sc); + a10_gpio_set_function(sc, pin, A10_GPIO_PULLDOWN); + A10_GPIO_UNLOCK(sc); + + return (0); +} Copied: stable/10/sys/arm/allwinner/a10_gpio.h (from r262708, head/sys/arm/allwinner/a10_gpio.h) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/10/sys/arm/allwinner/a10_gpio.h Fri May 16 23:27:18 2014 (r266274, copy of r262708, head/sys/arm/allwinner/a10_gpio.h) @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2013 Ganbold Tsagaankhuu + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ + */ + +#ifndef _A10_GPIO_H_ +#define _A10_GPIO_H_ + +int a10_emac_gpio_config(uint32_t pin); + +#endif Copied: stable/10/sys/arm/allwinner/a10_sramc.c (from r262709, head/sys/arm/allwinner/a10_sramc.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/10/sys/arm/allwinner/a10_sramc.c Fri May 16 23:27:18 2014 (r266274, copy of r262709, head/sys/arm/allwinner/a10_sramc.c) @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2013 Ganbold Tsagaankhuu + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "a10_sramc.h" + +#define SRAM_CTL1_CFG 0x04 + +struct a10_sramc_softc { + struct resource *res; + bus_space_tag_t bst; + bus_space_handle_t bsh; +}; + +static struct a10_sramc_softc *a10_sramc_sc; + +#define sramc_read_4(sc, reg) \ + bus_space_read_4((sc)->bst, (sc)->bsh, (reg)) +#define sramc_write_4(sc, reg, val) \ + bus_space_write_4((sc)->bst, (sc)->bsh, (reg), (val)) + + +static int +a10_sramc_probe(device_t dev) +{ + + if (ofw_bus_is_compatible(dev, "allwinner,sun4i-sramc")) { + device_set_desc(dev, "Allwinner sramc module"); + return (BUS_PROBE_DEFAULT); + } + + return (ENXIO); +} + +static int +a10_sramc_attach(device_t dev) +{ + struct a10_sramc_softc *sc = device_get_softc(dev); + int rid = 0; + + sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (!sc->res) { + device_printf(dev, "could not allocate resource\n"); + return (ENXIO); + } + + sc->bst = rman_get_bustag(sc->res); + sc->bsh = rman_get_bushandle(sc->res); + + a10_sramc_sc = sc; + + return (0); +} + +static device_method_t a10_sramc_methods[] = { + DEVMETHOD(device_probe, a10_sramc_probe), + DEVMETHOD(device_attach, a10_sramc_attach), + { 0, 0 } +}; + +static driver_t a10_sramc_driver = { + "a10_sramc", + a10_sramc_methods, + sizeof(struct a10_sramc_softc), +}; + +static devclass_t a10_sramc_devclass; + +DRIVER_MODULE(a10_sramc, simplebus, a10_sramc_driver, a10_sramc_devclass, 0, 0); + +int +a10_map_to_emac(void) +{ + struct a10_sramc_softc *sc = a10_sramc_sc; + uint32_t reg_value; + + if (sc == NULL) + return (ENXIO); + + /* Map SRAM to EMAC, set bit 2 and 4. */ + reg_value = sramc_read_4(sc, SRAM_CTL1_CFG); + reg_value |= 0x5 << 2; + sramc_write_4(sc, SRAM_CTL1_CFG, reg_value); + + return (0); +} Copied: stable/10/sys/arm/allwinner/a10_sramc.h (from r262709, head/sys/arm/allwinner/a10_sramc.h) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/10/sys/arm/allwinner/a10_sramc.h Fri May 16 23:27:18 2014 (r266274, copy of r262709, head/sys/arm/allwinner/a10_sramc.h) @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2013 Ganbold Tsagaankhuu + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ + */ + +#ifndef _A10_SRAMC_H_ +#define _A10_SRAMC_H_ + +int a10_map_to_emac(void); + +#endif Modified: stable/10/sys/arm/allwinner/a20/files.a20 ============================================================================== --- stable/10/sys/arm/allwinner/a20/files.a20 Fri May 16 22:55:01 2014 (r266273) +++ stable/10/sys/arm/allwinner/a20/files.a20 Fri May 16 23:27:18 2014 (r266274) @@ -12,8 +12,10 @@ arm/arm/gic.c standard arm/allwinner/a20/a20_cpu_cfg.c standard arm/allwinner/a10_clk.c standard +arm/allwinner/a10_sramc.c standard arm/allwinner/a10_gpio.c optional gpio arm/allwinner/a10_ehci.c optional ehci +arm/allwinner/if_emac.c optional emac arm/allwinner/a10_wdog.c standard arm/allwinner/timer.c standard arm/allwinner/bus_space.c standard Modified: stable/10/sys/arm/allwinner/files.a10 ============================================================================== --- stable/10/sys/arm/allwinner/files.a10 Fri May 16 22:55:01 2014 (r266273) +++ stable/10/sys/arm/allwinner/files.a10 Fri May 16 23:27:18 2014 (r266274) @@ -11,8 +11,10 @@ arm/arm/irq_dispatch.S standard arm/allwinner/a20/a20_cpu_cfg.c standard arm/allwinner/a10_clk.c standard +arm/allwinner/a10_sramc.c standard arm/allwinner/a10_gpio.c optional gpio arm/allwinner/a10_ehci.c optional ehci +arm/allwinner/if_emac.c optional emac arm/allwinner/a10_wdog.c standard arm/allwinner/timer.c standard arm/allwinner/aintc.c standard Copied: stable/10/sys/arm/allwinner/if_emac.c (from r262710, head/sys/arm/allwinner/if_emac.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/10/sys/arm/allwinner/if_emac.c Fri May 16 23:27:18 2014 (r266274, copy of r262710, head/sys/arm/allwinner/if_emac.c) @@ -0,0 +1,1152 @@ +/*- + * Copyright (c) 2013 Ganbold Tsagaankhuu + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$ + */ + +/* A10/A20 EMAC driver */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#include +#include +#endif + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include "miibus_if.h" + +#include "gpio_if.h" + +#include "a10_clk.h" +#include "a10_sramc.h" +#include "a10_gpio.h" + +struct emac_softc { + struct ifnet *emac_ifp; + device_t emac_dev; + device_t emac_miibus; + bus_space_handle_t emac_handle; + bus_space_tag_t emac_tag; + struct resource *emac_res; + struct resource *emac_irq; + void *emac_intrhand; + int emac_if_flags; + struct mtx emac_mtx; + struct callout emac_tick_ch; + int emac_watchdog_timer; + int emac_rx_process_limit; + int emac_link; +}; + +static int emac_probe(device_t); +static int emac_attach(device_t); +static int emac_detach(device_t); +static int emac_shutdown(device_t); +static int emac_suspend(device_t); +static int emac_resume(device_t); + +static void emac_sys_setup(void); +static void emac_reset(struct emac_softc *); + +static void emac_init_locked(struct emac_softc *); +static void emac_start_locked(struct ifnet *); +static void emac_init(void *); +static void emac_stop_locked(struct emac_softc *); +static void emac_intr(void *); +static int emac_ioctl(struct ifnet *, u_long, caddr_t); + +static void emac_rxeof(struct emac_softc *, int); +static void emac_txeof(struct emac_softc *); + +static int emac_miibus_readreg(device_t, int, int); +static int emac_miibus_writereg(device_t, int, int, int); +static void emac_miibus_statchg(device_t); + +static int emac_ifmedia_upd(struct ifnet *); +static void emac_ifmedia_sts(struct ifnet *, struct ifmediareq *); + +static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); +static int sysctl_hw_emac_proc_limit(SYSCTL_HANDLER_ARGS); + +#define EMAC_READ_REG(sc, reg) \ + bus_space_read_4(sc->emac_tag, sc->emac_handle, reg) +#define EMAC_WRITE_REG(sc, reg, val) \ + bus_space_write_4(sc->emac_tag, sc->emac_handle, reg, val) + +static void +emac_sys_setup(void) +{ + int i; + + a10_clk_emac_activate(); + + /* + * Configure pin mux settings for MII. + * Pins PA0 from PA17. + */ + for (i = 0; i <= 17; i++) + a10_emac_gpio_config(i); + /* Map sram */ + a10_map_to_emac(); +} + +static void +emac_get_hwaddr(struct emac_softc *sc, uint8_t *hwaddr) +{ + uint32_t val0, val1, rnd; + + /* + * Try to get MAC address from running hardware. + * If there is something non-zero there just use it. + * + * Otherwise set the address to a convenient locally assigned address, + * 'bsd' + random 24 low-order bits. 'b' is 0x62, which has the locally + * assigned bit set, and the broadcast/multicast bit clear. + */ + val0 = EMAC_READ_REG(sc, EMAC_MAC_A0); + val1 = EMAC_READ_REG(sc, EMAC_MAC_A1); + if ((val0 | val1) != 0 && (val0 | val1) != 0xffffff) { + hwaddr[0] = (val1 >> 16) & 0xff; + hwaddr[1] = (val1 >> 8) & 0xff; + hwaddr[2] = (val1 >> 0) & 0xff; + hwaddr[3] = (val0 >> 16) & 0xff; + hwaddr[4] = (val0 >> 8) & 0xff; + hwaddr[5] = (val0 >> 0) & 0xff; + } else { + rnd = arc4random() & 0x00ffffff; + hwaddr[0] = 'b'; + hwaddr[1] = 's'; + hwaddr[2] = 'd'; + hwaddr[3] = (rnd >> 16) & 0xff; + hwaddr[4] = (rnd >> 8) & 0xff; + hwaddr[5] = (rnd >> 0) & 0xff; + } + if (bootverbose) + printf("MAC address: %s\n", ether_sprintf(hwaddr)); +} + +static void +emac_set_rx_mode(struct emac_softc *sc) +{ + struct ifnet *ifp; + struct ifmultiaddr *ifma; + uint32_t h, hashes[2]; + uint32_t rcr = 0; + + EMAC_ASSERT_LOCKED(sc); + + ifp = sc->emac_ifp; + + rcr = EMAC_READ_REG(sc, EMAC_RX_CTL); + + /* Unicast packet and DA filtering */ + rcr |= EMAC_RX_UCAD; + rcr |= EMAC_RX_DAF; + + hashes[0] = 0; + hashes[1] = 0; + if (ifp->if_flags & IFF_ALLMULTI) { + hashes[0] = 0xffffffff; + hashes[1] = 0xffffffff; + } else { + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &sc->emac_ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + h = ether_crc32_be(LLADDR((struct sockaddr_dl *) + ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; + hashes[h >> 5] |= 1 << (h & 0x1f); + } + if_maddr_runlock(ifp); + } + rcr |= EMAC_RX_MCO; + rcr |= EMAC_RX_MHF; + EMAC_WRITE_REG(sc, EMAC_RX_HASH0, hashes[0]); + EMAC_WRITE_REG(sc, EMAC_RX_HASH1, hashes[1]); + + if (ifp->if_flags & IFF_BROADCAST) { + rcr |= EMAC_RX_BCO; + rcr |= EMAC_RX_MCO; + } + + if (ifp->if_flags & IFF_PROMISC) + rcr |= EMAC_RX_PA; + else + rcr |= EMAC_RX_UCAD; + + EMAC_WRITE_REG(sc, EMAC_RX_CTL, rcr); +} + +static void +emac_reset(struct emac_softc *sc) +{ + + EMAC_WRITE_REG(sc, EMAC_CTL, 0); + DELAY(200); + EMAC_WRITE_REG(sc, EMAC_CTL, 1); + DELAY(200); +} + +static void +emac_txeof(struct emac_softc *sc) +{ + struct ifnet *ifp; + + EMAC_ASSERT_LOCKED(sc); + + ifp = sc->emac_ifp; + ifp->if_opackets++; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + /* Unarm watchdog timer if no TX */ + sc->emac_watchdog_timer = 0; +} + +static void +emac_rxeof(struct emac_softc *sc, int count) +{ + struct ifnet *ifp; + struct mbuf *m, *m0; + uint32_t reg_val, rxcount; + int16_t len; + uint16_t status; + int good_packet, i; + + ifp = sc->emac_ifp; + for (; count > 0 && + (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; count--) { + /* + * Race warning: The first packet might arrive with + * the interrupts disabled, but the second will fix + */ + rxcount = EMAC_READ_REG(sc, EMAC_RX_FBC); + if (!rxcount) { + /* Had one stuck? */ + rxcount = EMAC_READ_REG(sc, EMAC_RX_FBC); + if (!rxcount) + return; + } + /* Check packet header */ + reg_val = EMAC_READ_REG(sc, EMAC_RX_IO_DATA); + if (reg_val != EMAC_PACKET_HEADER) { + /* Packet header is wrong */ + if (bootverbose) + if_printf(ifp, "wrong packet header\n"); + /* Disable RX */ + reg_val = EMAC_READ_REG(sc, EMAC_CTL); + reg_val &= ~EMAC_CTL_RX_EN; + EMAC_WRITE_REG(sc, EMAC_CTL, reg_val); + + /* Flush RX FIFO */ + reg_val = EMAC_READ_REG(sc, EMAC_RX_CTL); + reg_val |= EMAC_RX_FLUSH_FIFO; + EMAC_WRITE_REG(sc, EMAC_RX_CTL, reg_val); + for (i = 100; i > 0; i--) { + DELAY(100); + if ((EMAC_READ_REG(sc, EMAC_RX_CTL) & + EMAC_RX_FLUSH_FIFO) == 0) + break; + } + if (i == 0) { + device_printf(sc->emac_dev, + "flush FIFO timeout\n"); + /* Reinitialize controller */ + emac_init_locked(sc); + return; + } + /* Enable RX */ + reg_val = EMAC_READ_REG(sc, EMAC_CTL); + reg_val |= EMAC_CTL_RX_EN; + EMAC_WRITE_REG(sc, EMAC_CTL, reg_val); + + return; + } + + good_packet = 1; + + /* Get packet size and status */ + reg_val = EMAC_READ_REG(sc, EMAC_RX_IO_DATA); + len = reg_val & 0xffff; + status = (reg_val >> 16) & 0xffff; + + if (len < 64) { + good_packet = 0; + if (bootverbose) + if_printf(ifp, + "bad packet: len = %i status = %i\n", + len, status); + ifp->if_ierrors++; + } +#if 0 + if (status & (EMAC_CRCERR | EMAC_LENERR)) { + good_packet = 0; + ifp->if_ierrors++; + if (status & EMAC_CRCERR) + if_printf(ifp, "crc error\n"); + if (status & EMAC_LENERR) + if_printf(ifp, "length error\n"); + } +#endif + if (good_packet) { + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) + return; + m->m_len = m->m_pkthdr.len = MCLBYTES; + + len -= ETHER_CRC_LEN; + + /* Copy entire frame to mbuf first. */ + bus_space_read_multi_4(sc->emac_tag, sc->emac_handle, + EMAC_RX_IO_DATA, mtod(m, uint32_t *), + roundup2(len, 4) / 4); + + m->m_pkthdr.rcvif = ifp; + m->m_len = m->m_pkthdr.len = len; + + /* + * Emac controller needs strict aligment, so to avoid + * copying over an entire frame to align, we allocate + * a new mbuf and copy ethernet header + IP header to + * the new mbuf. The new mbuf is prepended into the + * existing mbuf chain. + */ + if (m->m_len <= (MHLEN - ETHER_HDR_LEN)) { + bcopy(m->m_data, m->m_data + ETHER_HDR_LEN, + m->m_len); + m->m_data += ETHER_HDR_LEN; + } else if (m->m_len <= (MCLBYTES - ETHER_HDR_LEN) && + m->m_len > (MHLEN - ETHER_HDR_LEN)) { + MGETHDR(m0, M_NOWAIT, MT_DATA); + if (m0 != NULL) { + len = ETHER_HDR_LEN + + m->m_pkthdr.l2hlen; + bcopy(m->m_data, m0->m_data, len); + m->m_data += len; + m->m_len -= len; + m0->m_len = len; + M_MOVE_PKTHDR(m0, m); + m0->m_next = m; + m = m0; + } else { + ifp->if_ierrors++; + m_freem(m); + m = NULL; + continue; + } + } else if (m->m_len > EMAC_MAC_MAXF) { + ifp->if_ierrors++; + m_freem(m); + m = NULL; + continue; + } + ifp->if_ipackets++; + EMAC_UNLOCK(sc); + (*ifp->if_input)(ifp, m); + EMAC_LOCK(sc); + } + } +} + +static void +emac_watchdog(struct emac_softc *sc) +{ + struct ifnet *ifp; + + EMAC_ASSERT_LOCKED(sc); + + if (sc->emac_watchdog_timer == 0 || --sc->emac_watchdog_timer) + return; + + ifp = sc->emac_ifp; + + if (sc->emac_link == 0) { + if (bootverbose) + if_printf(sc->emac_ifp, "watchdog timeout " + "(missed link)\n"); + } else + if_printf(sc->emac_ifp, "watchdog timeout -- resetting\n"); + + ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + emac_init_locked(sc); + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + emac_start_locked(ifp); +} + +static void +emac_tick(void *arg) +{ + struct emac_softc *sc; + struct mii_data *mii; + + sc = (struct emac_softc *)arg; + mii = device_get_softc(sc->emac_miibus); + mii_tick(mii); + + emac_watchdog(sc); + callout_reset(&sc->emac_tick_ch, hz, emac_tick, sc); +} + +static void +emac_init(void *xcs) +{ + struct emac_softc *sc; + + sc = (struct emac_softc *)xcs; + EMAC_LOCK(sc); + emac_init_locked(sc); + EMAC_UNLOCK(sc); +} + +static void +emac_init_locked(struct emac_softc *sc) +{ + struct ifnet *ifp; + struct mii_data *mii; + uint32_t reg_val; + uint8_t *eaddr; + + EMAC_ASSERT_LOCKED(sc); + + ifp = sc->emac_ifp; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return; + + /* Flush RX FIFO */ + reg_val = EMAC_READ_REG(sc, EMAC_RX_CTL); + reg_val |= EMAC_RX_FLUSH_FIFO; + EMAC_WRITE_REG(sc, EMAC_RX_CTL, reg_val); + DELAY(1); + + /* Soft reset MAC */ + reg_val = EMAC_READ_REG(sc, EMAC_MAC_CTL0); + reg_val &= (~EMAC_MAC_CTL0_SOFT_RST); + EMAC_WRITE_REG(sc, EMAC_MAC_CTL0, reg_val); + + /* Set MII clock */ + reg_val = EMAC_READ_REG(sc, EMAC_MAC_MCFG); + reg_val &= (~(0xf << 2)); + reg_val |= (0xd << 2); + EMAC_WRITE_REG(sc, EMAC_MAC_MCFG, reg_val); + + /* Clear RX counter */ + EMAC_WRITE_REG(sc, EMAC_RX_FBC, 0); + + /* Disable all interrupt and clear interrupt status */ + EMAC_WRITE_REG(sc, EMAC_INT_CTL, 0); + reg_val = EMAC_READ_REG(sc, EMAC_INT_STA); + EMAC_WRITE_REG(sc, EMAC_INT_STA, reg_val); + DELAY(1); + + /* Set up TX */ + reg_val = EMAC_READ_REG(sc, EMAC_TX_MODE); + reg_val |= EMAC_TX_AB_M; + reg_val &= EMAC_TX_TM; + EMAC_WRITE_REG(sc, EMAC_TX_MODE, reg_val); + + /* Set up RX */ + reg_val = EMAC_READ_REG(sc, EMAC_RX_CTL); + reg_val |= EMAC_RX_SETUP; + reg_val &= EMAC_RX_TM; + EMAC_WRITE_REG(sc, EMAC_RX_CTL, reg_val); + + /* Set up MAC CTL0. */ + reg_val = EMAC_READ_REG(sc, EMAC_MAC_CTL0); + reg_val |= EMAC_MAC_CTL0_SETUP; + EMAC_WRITE_REG(sc, EMAC_MAC_CTL0, reg_val); + + /* Set up MAC CTL1. */ + reg_val = EMAC_READ_REG(sc, EMAC_MAC_CTL1); + reg_val |= EMAC_MAC_CTL1_SETUP; + EMAC_WRITE_REG(sc, EMAC_MAC_CTL1, reg_val); + + /* Set up IPGT */ + EMAC_WRITE_REG(sc, EMAC_MAC_IPGT, EMAC_MAC_IPGT_FD); + + /* Set up IPGR */ + EMAC_WRITE_REG(sc, EMAC_MAC_IPGR, EMAC_MAC_NBTB_IPG2 | + (EMAC_MAC_NBTB_IPG1 << 8)); + + /* Set up Collison window */ + EMAC_WRITE_REG(sc, EMAC_MAC_CLRT, EMAC_MAC_RM | (EMAC_MAC_CW << 8)); + + /* Set up Max Frame Length */ + EMAC_WRITE_REG(sc, EMAC_MAC_MAXF, EMAC_MAC_MFL); + + /* Setup ethernet address */ + eaddr = IF_LLADDR(ifp); + EMAC_WRITE_REG(sc, EMAC_MAC_A1, eaddr[0] << 16 | + eaddr[1] << 8 | eaddr[2]); + EMAC_WRITE_REG(sc, EMAC_MAC_A0, eaddr[3] << 16 | + eaddr[4] << 8 | eaddr[5]); + + /* Setup rx filter */ + emac_set_rx_mode(sc); + + /* Enable RX/TX0/RX Hlevel interrupt */ + reg_val = EMAC_READ_REG(sc, EMAC_INT_CTL); + reg_val |= EMAC_INT_EN; + EMAC_WRITE_REG(sc, EMAC_INT_CTL, reg_val); + + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + sc->emac_link = 0; + + /* Switch to the current media. */ + mii = device_get_softc(sc->emac_miibus); + mii_mediachg(mii); + + callout_reset(&sc->emac_tick_ch, hz, emac_tick, sc); +} + + +static void +emac_start(struct ifnet *ifp) +{ + struct emac_softc *sc; + + sc = ifp->if_softc; + EMAC_LOCK(sc); + emac_start_locked(ifp); + EMAC_UNLOCK(sc); +} + +static void +emac_start_locked(struct ifnet *ifp) +{ + struct emac_softc *sc; + struct mbuf *m, *m0; + uint32_t reg_val; + + sc = ifp->if_softc; + if (ifp->if_drv_flags & IFF_DRV_OACTIVE) + return; + if (sc->emac_link == 0) + return; + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + return; + + /* Select channel */ + EMAC_WRITE_REG(sc, EMAC_TX_INS, 0); + + /* + * Emac controller wants 4 byte aligned TX buffers. + * We have to copy pretty much all the time. + */ + if (m->m_next != NULL || (mtod(m, uintptr_t) & 3) != 0) { + m0 = m_defrag(m, M_NOWAIT); + if (m0 == NULL) { + m_freem(m); + m = NULL; + return; + } + m = m0; + } + /* Write data */ + bus_space_write_multi_4(sc->emac_tag, sc->emac_handle, + EMAC_TX_IO_DATA, mtod(m, uint32_t *), + roundup2(m->m_len, 4) / 4); + + /* Send the data lengh. */ + EMAC_WRITE_REG(sc, EMAC_TX_PL0, m->m_len); + + /* Start translate from fifo to phy. */ + reg_val = EMAC_READ_REG(sc, EMAC_TX_CTL0); + reg_val |= 1; + EMAC_WRITE_REG(sc, EMAC_TX_CTL0, reg_val); + + /* Set timeout */ + sc->emac_watchdog_timer = 5; + + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + BPF_MTAP(ifp, m); + m_freem(m); +} + +static void +emac_stop_locked(struct emac_softc *sc) +{ + struct ifnet *ifp; + uint32_t reg_val; + *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***