Module Name: src Committed By: jakllsch Date: Thu Oct 26 01:16:32 UTC 2017
Added Files: src/sys/arch/arm/ti: files.ti if_cpsw.c ti_com.c ti_omapintc.c ti_omaptimer.c ti_platform.c ti_platform.h src/sys/arch/evbarm/conf: TI files.ti mk.ti std.ti src/sys/arch/evbarm/ti: genassym.cf ti_start.S Log Message: Initial FDT support for TI's ARM SoCs. Currently supports only limited functionality on AM335x. To generate a diff of this commit: cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/ti/files.ti \ src/sys/arch/arm/ti/if_cpsw.c src/sys/arch/arm/ti/ti_com.c \ src/sys/arch/arm/ti/ti_omapintc.c src/sys/arch/arm/ti/ti_omaptimer.c \ src/sys/arch/arm/ti/ti_platform.c src/sys/arch/arm/ti/ti_platform.h cvs rdiff -u -r0 -r1.1 src/sys/arch/evbarm/conf/TI \ src/sys/arch/evbarm/conf/files.ti src/sys/arch/evbarm/conf/mk.ti \ src/sys/arch/evbarm/conf/std.ti cvs rdiff -u -r0 -r1.1 src/sys/arch/evbarm/ti/genassym.cf \ src/sys/arch/evbarm/ti/ti_start.S Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Added files: Index: src/sys/arch/arm/ti/files.ti diff -u /dev/null src/sys/arch/arm/ti/files.ti:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/arm/ti/files.ti Thu Oct 26 01:16:32 2017 @@ -0,0 +1,34 @@ +# $NetBSD: files.ti,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ +# + +include arch/arm/pic/files.pic +include arch/arm/cortex/files.cortex + +file arch/arm/arm32/arm32_boot.c +file arch/arm/arm32/arm32_kvminit.c +file arch/arm/arm32/arm32_reboot.c +file arch/arm/arm32/irq_dispatch.S + +file arch/arm/arm32/armv7_generic_space.c +file arch/arm/arm32/armv7_generic_dma.c +file arch/arm/arm/bus_space_a4x.S + +file arch/arm/ti/ti_platform.c + +# interrupt controller +device omapintc: pic, pic_splfuncs +attach omapintc at fdt +file arch/arm/ti/ti_omapintc.c omapintc + +# UART +attach com at fdt with ti_com +file arch/arm/ti/ti_com.c ti_com needs-flag + +# Timer +device omaptimer +attach omaptimer at fdt +file arch/arm/ti/ti_omaptimer.c omaptimer + +device cpsw: ether, ifnet, arp, mii, mii_phy +attach cpsw at fdt +file arch/arm/ti/if_cpsw.c cpsw Index: src/sys/arch/arm/ti/if_cpsw.c diff -u /dev/null src/sys/arch/arm/ti/if_cpsw.c:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/arm/ti/if_cpsw.c Thu Oct 26 01:16:32 2017 @@ -0,0 +1,1578 @@ +/* $NetBSD: if_cpsw.c,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ */ + +/* + * Copyright (c) 2013 Jonathan A. Kollasch + * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + */ + +/*- + * Copyright (c) 2012 Damjan Marion <dmar...@freebsd.org> + * 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. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(1, "$NetBSD: if_cpsw.c,v 1.1 2017/10/26 01:16:32 jakllsch Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/intr.h> +#include <sys/kmem.h> +#include <sys/mutex.h> +#include <sys/systm.h> +#include <sys/kernel.h> + +#include <net/if.h> +#include <net/if_ether.h> +#include <net/if_media.h> +#include <net/bpf.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#if 0 +#include <arch/arm/omap/omap2_obiovar.h> +#else +#include <dev/fdt/fdtvar.h> +#endif +#include <arch/arm/omap/if_cpswreg.h> +#include <arch/arm/omap/sitara_cmreg.h> +#include <arch/arm/omap/sitara_cm.h> + +#define ETHER_ALIGN (roundup2(ETHER_HDR_LEN, sizeof(uint32_t)) - ETHER_HDR_LEN) + +#define CPSW_TXFRAGS 16 + +#define CPSW_CPPI_RAM_SIZE (0x2000) +#define CPSW_CPPI_RAM_TXDESCS_SIZE (CPSW_CPPI_RAM_SIZE/2) +#define CPSW_CPPI_RAM_RXDESCS_SIZE \ + (CPSW_CPPI_RAM_SIZE - CPSW_CPPI_RAM_TXDESCS_SIZE) +#define CPSW_CPPI_RAM_TXDESCS_BASE (CPSW_CPPI_RAM_OFFSET + 0x0000) +#define CPSW_CPPI_RAM_RXDESCS_BASE \ + (CPSW_CPPI_RAM_OFFSET + CPSW_CPPI_RAM_TXDESCS_SIZE) + +#define CPSW_NTXDESCS (CPSW_CPPI_RAM_TXDESCS_SIZE/sizeof(struct cpsw_cpdma_bd)) +#define CPSW_NRXDESCS (CPSW_CPPI_RAM_RXDESCS_SIZE/sizeof(struct cpsw_cpdma_bd)) + +CTASSERT(powerof2(CPSW_NTXDESCS)); +CTASSERT(powerof2(CPSW_NRXDESCS)); + +#define CPSW_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN) + +#define TXDESC_NEXT(x) cpsw_txdesc_adjust((x), 1) +#define TXDESC_PREV(x) cpsw_txdesc_adjust((x), -1) + +#define RXDESC_NEXT(x) cpsw_rxdesc_adjust((x), 1) +#define RXDESC_PREV(x) cpsw_rxdesc_adjust((x), -1) + +struct cpsw_ring_data { + bus_dmamap_t tx_dm[CPSW_NTXDESCS]; + struct mbuf *tx_mb[CPSW_NTXDESCS]; + bus_dmamap_t rx_dm[CPSW_NRXDESCS]; + struct mbuf *rx_mb[CPSW_NRXDESCS]; +}; + +struct cpsw_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + bus_size_t sc_bss; + bus_dma_tag_t sc_bdt; + bus_space_handle_t sc_bsh_txdescs; + bus_space_handle_t sc_bsh_rxdescs; + bus_addr_t sc_txdescs_pa; + bus_addr_t sc_rxdescs_pa; + struct ethercom sc_ec; + struct mii_data sc_mii; + bool sc_phy_has_1000t; + bool sc_attached; + callout_t sc_tick_ch; + void *sc_ih; + struct cpsw_ring_data *sc_rdp; + volatile u_int sc_txnext; + volatile u_int sc_txhead; + volatile u_int sc_rxhead; + void *sc_rxthih; + void *sc_rxih; + void *sc_txih; + void *sc_miscih; + void *sc_txpad; + bus_dmamap_t sc_txpad_dm; +#define sc_txpad_pa sc_txpad_dm->dm_segs[0].ds_addr + uint8_t sc_enaddr[ETHER_ADDR_LEN]; + volatile bool sc_txrun; + volatile bool sc_rxrun; + volatile bool sc_txeoq; + volatile bool sc_rxeoq; +}; + +static int cpsw_match(device_t, cfdata_t, void *); +static void cpsw_attach(device_t, device_t, void *); +static int cpsw_detach(device_t, int); + +static void cpsw_start(struct ifnet *); +static int cpsw_ioctl(struct ifnet *, u_long, void *); +static void cpsw_watchdog(struct ifnet *); +static int cpsw_init(struct ifnet *); +static void cpsw_stop(struct ifnet *, int); + +static int cpsw_mii_readreg(device_t, int, int); +static void cpsw_mii_writereg(device_t, int, int, int); +static void cpsw_mii_statchg(struct ifnet *); + +static int cpsw_new_rxbuf(struct cpsw_softc * const, const u_int); +static void cpsw_tick(void *); + +static int cpsw_rxthintr(void *); +static int cpsw_rxintr(void *); +static int cpsw_txintr(void *); +static int cpsw_miscintr(void *); + +/* ALE support */ +#define CPSW_MAX_ALE_ENTRIES 1024 + +static int cpsw_ale_update_addresses(struct cpsw_softc *, int purge); + +CFATTACH_DECL_NEW(cpsw, sizeof(struct cpsw_softc), + cpsw_match, cpsw_attach, cpsw_detach, NULL); + +#undef KERNHIST +#include <sys/kernhist.h> +KERNHIST_DEFINE(cpswhist); + +#ifdef KERNHIST +#define KERNHIST_CALLED_5(NAME, i, j, k, l) \ +do { \ + _kernhist_call = atomic_inc_uint_nv(&_kernhist_cnt); \ + KERNHIST_LOG(NAME, "called! %x %x %x %x", i, j, k, l); \ +} while (/*CONSTCOND*/ 0) +#else +#define KERNHIST_CALLED_5(NAME, i, j, k, l) +#endif + +static inline u_int +cpsw_txdesc_adjust(u_int x, int y) +{ + return (((x) + y) & (CPSW_NTXDESCS - 1)); +} + +static inline u_int +cpsw_rxdesc_adjust(u_int x, int y) +{ + return (((x) + y) & (CPSW_NRXDESCS - 1)); +} + +static inline uint32_t +cpsw_read_4(struct cpsw_softc * const sc, bus_size_t const offset) +{ + return bus_space_read_4(sc->sc_bst, sc->sc_bsh, offset); +} + +static inline void +cpsw_write_4(struct cpsw_softc * const sc, bus_size_t const offset, + uint32_t const value) +{ + bus_space_write_4(sc->sc_bst, sc->sc_bsh, offset, value); +} + +static inline void +cpsw_set_txdesc_next(struct cpsw_softc * const sc, const u_int i, uint32_t n) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i + 0; + + KERNHIST_FUNC(__func__); + KERNHIST_CALLED_5(cpswhist, sc, i, n, 0); + + bus_space_write_4(sc->sc_bst, sc->sc_bsh_txdescs, o, n); +} + +static inline void +cpsw_set_rxdesc_next(struct cpsw_softc * const sc, const u_int i, uint32_t n) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i + 0; + + KERNHIST_FUNC(__func__); + KERNHIST_CALLED_5(cpswhist, sc, i, n, 0); + + bus_space_write_4(sc->sc_bst, sc->sc_bsh_rxdescs, o, n); +} + +static inline void +cpsw_get_txdesc(struct cpsw_softc * const sc, const u_int i, + struct cpsw_cpdma_bd * const bdp) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i; + uint32_t * const dp = bdp->word; + const bus_size_t c = __arraycount(bdp->word); + + KERNHIST_FUNC(__func__); + KERNHIST_CALLED_5(cpswhist, sc, i, bdp, 0); + + bus_space_read_region_4(sc->sc_bst, sc->sc_bsh_txdescs, o, dp, c); + KERNHIST_LOG(cpswhist, "%08x %08x %08x %08x\n", + dp[0], dp[1], dp[2], dp[3]); +} + +static inline void +cpsw_set_txdesc(struct cpsw_softc * const sc, const u_int i, + struct cpsw_cpdma_bd * const bdp) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i; + uint32_t * const dp = bdp->word; + const bus_size_t c = __arraycount(bdp->word); + + KERNHIST_FUNC(__func__); + KERNHIST_CALLED_5(cpswhist, sc, i, bdp, 0); + KERNHIST_LOG(cpswhist, "%08x %08x %08x %08x\n", + dp[0], dp[1], dp[2], dp[3]); + + bus_space_write_region_4(sc->sc_bst, sc->sc_bsh_txdescs, o, dp, c); +} + +static inline void +cpsw_get_rxdesc(struct cpsw_softc * const sc, const u_int i, + struct cpsw_cpdma_bd * const bdp) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i; + uint32_t * const dp = bdp->word; + const bus_size_t c = __arraycount(bdp->word); + + KERNHIST_FUNC(__func__); + KERNHIST_CALLED_5(cpswhist, sc, i, bdp, 0); + + bus_space_read_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, o, dp, c); + + KERNHIST_LOG(cpswhist, "%08x %08x %08x %08x\n", + dp[0], dp[1], dp[2], dp[3]); +} + +static inline void +cpsw_set_rxdesc(struct cpsw_softc * const sc, const u_int i, + struct cpsw_cpdma_bd * const bdp) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i; + uint32_t * const dp = bdp->word; + const bus_size_t c = __arraycount(bdp->word); + + KERNHIST_FUNC(__func__); + KERNHIST_CALLED_5(cpswhist, sc, i, bdp, 0); + KERNHIST_LOG(cpswhist, "%08x %08x %08x %08x\n", + dp[0], dp[1], dp[2], dp[3]); + + bus_space_write_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, o, dp, c); +} + +static inline bus_addr_t +cpsw_txdesc_paddr(struct cpsw_softc * const sc, u_int x) +{ + KASSERT(x < CPSW_NTXDESCS); + return sc->sc_txdescs_pa + sizeof(struct cpsw_cpdma_bd) * x; +} + +static inline bus_addr_t +cpsw_rxdesc_paddr(struct cpsw_softc * const sc, u_int x) +{ + KASSERT(x < CPSW_NRXDESCS); + return sc->sc_rxdescs_pa + sizeof(struct cpsw_cpdma_bd) * x; +} + + +static int +cpsw_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + static const char * const compatible[] = { + "ti,am335x-cpsw", + "ti,cpsw", + NULL + }; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static bool +cpsw_phy_has_1000t(struct cpsw_softc * const sc) +{ + struct ifmedia_entry *ifm; + + TAILQ_FOREACH(ifm, &sc->sc_mii.mii_media.ifm_list, ifm_list) { + if (IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_T) + return true; + } + return false; +} + +static int +cpsw_detach(device_t self, int flags) +{ + struct cpsw_softc * const sc = device_private(self); + struct ifnet *ifp = &sc->sc_ec.ec_if; + u_int i; + + /* Succeed now if there's no work to do. */ + if (!sc->sc_attached) + return 0; + + sc->sc_attached = false; + + /* Stop the interface. Callouts are stopped in it. */ + cpsw_stop(ifp, 1); + + /* Destroy our callout. */ + callout_destroy(&sc->sc_tick_ch); + + /* Let go of the interrupts */ + intr_disestablish(sc->sc_rxthih); + intr_disestablish(sc->sc_rxih); + intr_disestablish(sc->sc_txih); + intr_disestablish(sc->sc_miscih); + + /* Delete all media. */ + ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY); + + ether_ifdetach(ifp); + if_detach(ifp); + + /* Free the packet padding buffer */ + kmem_free(sc->sc_txpad, ETHER_MIN_LEN); + bus_dmamap_destroy(sc->sc_bdt, sc->sc_txpad_dm); + + /* Destroy all the descriptors */ + for (i = 0; i < CPSW_NTXDESCS; i++) + bus_dmamap_destroy(sc->sc_bdt, sc->sc_rdp->tx_dm[i]); + for (i = 0; i < CPSW_NRXDESCS; i++) + bus_dmamap_destroy(sc->sc_bdt, sc->sc_rdp->rx_dm[i]); + kmem_free(sc->sc_rdp, sizeof(*sc->sc_rdp)); + + /* Unmap */ + bus_space_unmap(sc->sc_bst, sc->sc_bsh, sc->sc_bss); + + + return 0; +} + +static void +cpsw_attach(device_t parent, device_t self, void *aux) +{ + struct fdt_attach_args * const faa = aux; + struct cpsw_softc * const sc = device_private(self); + prop_dictionary_t dict = device_properties(self); + struct ethercom * const ec = &sc->sc_ec; + struct ifnet * const ifp = &ec->ec_if; + const int phandle = faa->faa_phandle; + bus_addr_t addr; + bus_size_t size; + int error; + u_int i; + + KERNHIST_INIT(cpswhist, 4096); + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + sc->sc_dev = self; + + aprint_normal(": TI Layer 2 3-Port Switch\n"); + aprint_naive("\n"); + + callout_init(&sc->sc_tick_ch, 0); + callout_setfunc(&sc->sc_tick_ch, cpsw_tick, sc); + + prop_data_t eaprop = prop_dictionary_get(dict, "mac-address"); + if (eaprop == NULL) { +#if 0 + /* grab mac_id0 from AM335x control module */ + uint32_t reg_lo, reg_hi; + + if (sitara_cm_reg_read_4(OMAP2SCM_MAC_ID0_LO, ®_lo) == 0 && + sitara_cm_reg_read_4(OMAP2SCM_MAC_ID0_HI, ®_hi) == 0) { + sc->sc_enaddr[0] = (reg_hi >> 0) & 0xff; + sc->sc_enaddr[1] = (reg_hi >> 8) & 0xff; + sc->sc_enaddr[2] = (reg_hi >> 16) & 0xff; + sc->sc_enaddr[3] = (reg_hi >> 24) & 0xff; + sc->sc_enaddr[4] = (reg_lo >> 0) & 0xff; + sc->sc_enaddr[5] = (reg_lo >> 8) & 0xff; + } else +#endif + { + aprint_error_dev(sc->sc_dev, + "using fake station address\n"); + /* 'N' happens to have the Local bit set */ +#if 0 + sc->sc_enaddr[0] = 'N'; + sc->sc_enaddr[1] = 'e'; + sc->sc_enaddr[2] = 't'; + sc->sc_enaddr[3] = 'B'; + sc->sc_enaddr[4] = 'S'; + sc->sc_enaddr[5] = 'D'; +#else + /* XXX Glor */ + sc->sc_enaddr[0] = 0xd4; + sc->sc_enaddr[1] = 0x94; + sc->sc_enaddr[2] = 0xa1; + sc->sc_enaddr[3] = 0x97; + sc->sc_enaddr[4] = 0x03; + sc->sc_enaddr[5] = 0x94; +#endif + } + } else { + KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); + KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); + memcpy(sc->sc_enaddr, prop_data_data_nocopy(eaprop), + ETHER_ADDR_LEN); + } + +#if 0 + sc->sc_rxthih = intr_establish(oa->obio_intrbase + CPSW_INTROFF_RXTH, + IPL_VM, IST_LEVEL, cpsw_rxthintr, sc); + sc->sc_rxih = intr_establish(oa->obio_intrbase + CPSW_INTROFF_RX, + IPL_VM, IST_LEVEL, cpsw_rxintr, sc); + sc->sc_txih = intr_establish(oa->obio_intrbase + CPSW_INTROFF_TX, + IPL_VM, IST_LEVEL, cpsw_txintr, sc); + sc->sc_miscih = intr_establish(oa->obio_intrbase + CPSW_INTROFF_MISC, + IPL_VM, IST_LEVEL, cpsw_miscintr, sc); +#else +#define FDT_INTR_FLAGS 0 + sc->sc_rxthih = fdtbus_intr_establish(phandle, CPSW_INTROFF_RXTH, IPL_VM, FDT_INTR_FLAGS, cpsw_rxthintr, sc); + sc->sc_rxih = fdtbus_intr_establish(phandle, CPSW_INTROFF_RX, IPL_VM, FDT_INTR_FLAGS, cpsw_rxintr, sc); + sc->sc_txih = fdtbus_intr_establish(phandle, CPSW_INTROFF_TX, IPL_VM, FDT_INTR_FLAGS, cpsw_txintr, sc); + sc->sc_miscih = fdtbus_intr_establish(phandle, CPSW_INTROFF_MISC, IPL_VM, FDT_INTR_FLAGS, cpsw_miscintr, sc); +#endif + + sc->sc_bst = faa->faa_bst; + sc->sc_bss = size; + sc->sc_bdt = faa->faa_dmat; + + error = bus_space_map(sc->sc_bst, addr, size, 0, + &sc->sc_bsh); + if (error) { + aprint_error_dev(sc->sc_dev, + "can't map registers: %d\n", error); + return; + } + + sc->sc_txdescs_pa = addr + CPSW_CPPI_RAM_TXDESCS_BASE; + error = bus_space_subregion(sc->sc_bst, sc->sc_bsh, + CPSW_CPPI_RAM_TXDESCS_BASE, CPSW_CPPI_RAM_TXDESCS_SIZE, + &sc->sc_bsh_txdescs); + if (error) { + aprint_error_dev(sc->sc_dev, + "can't subregion tx ring SRAM: %d\n", error); + return; + } + aprint_debug_dev(sc->sc_dev, "txdescs at %p\n", + (void *)sc->sc_bsh_txdescs); + + sc->sc_rxdescs_pa = addr + CPSW_CPPI_RAM_RXDESCS_BASE; + error = bus_space_subregion(sc->sc_bst, sc->sc_bsh, + CPSW_CPPI_RAM_RXDESCS_BASE, CPSW_CPPI_RAM_RXDESCS_SIZE, + &sc->sc_bsh_rxdescs); + if (error) { + aprint_error_dev(sc->sc_dev, + "can't subregion rx ring SRAM: %d\n", error); + return; + } + aprint_debug_dev(sc->sc_dev, "rxdescs at %p\n", + (void *)sc->sc_bsh_rxdescs); + + sc->sc_rdp = kmem_alloc(sizeof(*sc->sc_rdp), KM_SLEEP); + + for (i = 0; i < CPSW_NTXDESCS; i++) { + if ((error = bus_dmamap_create(sc->sc_bdt, MCLBYTES, + CPSW_TXFRAGS, MCLBYTES, 0, 0, + &sc->sc_rdp->tx_dm[i])) != 0) { + aprint_error_dev(sc->sc_dev, + "unable to create tx DMA map: %d\n", error); + } + sc->sc_rdp->tx_mb[i] = NULL; + } + + for (i = 0; i < CPSW_NRXDESCS; i++) { + if ((error = bus_dmamap_create(sc->sc_bdt, MCLBYTES, 1, + MCLBYTES, 0, 0, &sc->sc_rdp->rx_dm[i])) != 0) { + aprint_error_dev(sc->sc_dev, + "unable to create rx DMA map: %d\n", error); + } + sc->sc_rdp->rx_mb[i] = NULL; + } + + sc->sc_txpad = kmem_zalloc(ETHER_MIN_LEN, KM_SLEEP); + bus_dmamap_create(sc->sc_bdt, ETHER_MIN_LEN, 1, ETHER_MIN_LEN, 0, + BUS_DMA_WAITOK, &sc->sc_txpad_dm); + bus_dmamap_load(sc->sc_bdt, sc->sc_txpad_dm, sc->sc_txpad, + ETHER_MIN_LEN, NULL, BUS_DMA_WAITOK|BUS_DMA_WRITE); + bus_dmamap_sync(sc->sc_bdt, sc->sc_txpad_dm, 0, ETHER_MIN_LEN, + BUS_DMASYNC_PREWRITE); + + aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", + ether_sprintf(sc->sc_enaddr)); + + strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); + ifp->if_softc = sc; + ifp->if_capabilities = 0; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_start = cpsw_start; + ifp->if_ioctl = cpsw_ioctl; + ifp->if_init = cpsw_init; + ifp->if_stop = cpsw_stop; + ifp->if_watchdog = cpsw_watchdog; + IFQ_SET_READY(&ifp->if_snd); + + cpsw_stop(ifp, 0); + + sc->sc_mii.mii_ifp = ifp; + sc->sc_mii.mii_readreg = cpsw_mii_readreg; + sc->sc_mii.mii_writereg = cpsw_mii_writereg; + sc->sc_mii.mii_statchg = cpsw_mii_statchg; + + sc->sc_ec.ec_mii = &sc->sc_mii; + ifmedia_init(&sc->sc_mii.mii_media, 0, ether_mediachange, + ether_mediastatus); + + /* Initialize MDIO */ + cpsw_write_4(sc, MDIOCONTROL, + MDIOCTL_ENABLE | MDIOCTL_FAULTENB | MDIOCTL_CLKDIV(0xff)); + /* Clear ALE */ + cpsw_write_4(sc, CPSW_ALE_CONTROL, ALECTL_CLEAR_TABLE); + + mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, 0, 0); + if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { + aprint_error_dev(self, "no PHY found!\n"); + sc->sc_phy_has_1000t = false; + ifmedia_add(&sc->sc_mii.mii_media, + IFM_ETHER|IFM_MANUAL, 0, NULL); + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL); + } else { + sc->sc_phy_has_1000t = cpsw_phy_has_1000t(sc); + if (sc->sc_phy_has_1000t) { +#if 0 + aprint_normal_dev(sc->sc_dev, "1000baseT PHY found. " + "Setting RGMII Mode\n"); + /* + * Select the Interface RGMII Mode in the Control + * Module + */ + sitara_cm_reg_write_4(CPSW_GMII_SEL, + GMIISEL_GMII2_SEL(RGMII_MODE) | + GMIISEL_GMII1_SEL(RGMII_MODE)); +#endif + } + + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO); + } + + if_attach(ifp); + if_deferred_start_init(ifp, NULL); + ether_ifattach(ifp, sc->sc_enaddr); + + /* The attach is successful. */ + sc->sc_attached = true; + + return; +} + +static void +cpsw_start(struct ifnet *ifp) +{ + struct cpsw_softc * const sc = ifp->if_softc; + struct cpsw_ring_data * const rdp = sc->sc_rdp; + struct cpsw_cpdma_bd bd; + uint32_t * const dw = bd.word; + struct mbuf *m; + bus_dmamap_t dm; + u_int eopi __diagused = ~0; + u_int seg; + u_int txfree; + int txstart = -1; + int error; + bool pad; + u_int mlen; + + KERNHIST_FUNC(__func__); + KERNHIST_CALLED_5(cpswhist, sc, 0, 0, 0); + + if (__predict_false((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != + IFF_RUNNING)) { + return; + } + + if (sc->sc_txnext >= sc->sc_txhead) + txfree = CPSW_NTXDESCS - 1 + sc->sc_txhead - sc->sc_txnext; + else + txfree = sc->sc_txhead - sc->sc_txnext - 1; + + KERNHIST_LOG(cpswhist, "start txf %x txh %x txn %x txr %x\n", + txfree, sc->sc_txhead, sc->sc_txnext, sc->sc_txrun); + + while (txfree > 0) { + IFQ_POLL(&ifp->if_snd, m); + if (m == NULL) + break; + + dm = rdp->tx_dm[sc->sc_txnext]; + + error = bus_dmamap_load_mbuf(sc->sc_bdt, dm, m, BUS_DMA_NOWAIT); + if (error == EFBIG) { + device_printf(sc->sc_dev, "won't fit\n"); + IFQ_DEQUEUE(&ifp->if_snd, m); + m_freem(m); + ifp->if_oerrors++; + continue; + } else if (error != 0) { + device_printf(sc->sc_dev, "error\n"); + break; + } + + if (dm->dm_nsegs + 1 >= txfree) { + ifp->if_flags |= IFF_OACTIVE; + bus_dmamap_unload(sc->sc_bdt, dm); + break; + } + + mlen = m_length(m); + pad = mlen < CPSW_PAD_LEN; + + KASSERT(rdp->tx_mb[sc->sc_txnext] == NULL); + rdp->tx_mb[sc->sc_txnext] = m; + IFQ_DEQUEUE(&ifp->if_snd, m); + + bus_dmamap_sync(sc->sc_bdt, dm, 0, dm->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + if (txstart == -1) + txstart = sc->sc_txnext; + eopi = sc->sc_txnext; + for (seg = 0; seg < dm->dm_nsegs; seg++) { + dw[0] = cpsw_txdesc_paddr(sc, + TXDESC_NEXT(sc->sc_txnext)); + dw[1] = dm->dm_segs[seg].ds_addr; + dw[2] = dm->dm_segs[seg].ds_len; + dw[3] = 0; + + if (seg == 0) + dw[3] |= CPDMA_BD_SOP | CPDMA_BD_OWNER | + MAX(mlen, CPSW_PAD_LEN); + + if ((seg == dm->dm_nsegs - 1) && !pad) + dw[3] |= CPDMA_BD_EOP; + + cpsw_set_txdesc(sc, sc->sc_txnext, &bd); + txfree--; + eopi = sc->sc_txnext; + sc->sc_txnext = TXDESC_NEXT(sc->sc_txnext); + } + if (pad) { + dw[0] = cpsw_txdesc_paddr(sc, + TXDESC_NEXT(sc->sc_txnext)); + dw[1] = sc->sc_txpad_pa; + dw[2] = CPSW_PAD_LEN - mlen; + dw[3] = CPDMA_BD_EOP; + + cpsw_set_txdesc(sc, sc->sc_txnext, &bd); + txfree--; + eopi = sc->sc_txnext; + sc->sc_txnext = TXDESC_NEXT(sc->sc_txnext); + } + + bpf_mtap(ifp, m); + } + + if (txstart >= 0) { + ifp->if_timer = 5; + /* terminate the new chain */ + KASSERT(eopi == TXDESC_PREV(sc->sc_txnext)); + cpsw_set_txdesc_next(sc, TXDESC_PREV(sc->sc_txnext), 0); + KERNHIST_LOG(cpswhist, "CP %x HDP %x s %x e %x\n", + cpsw_read_4(sc, CPSW_CPDMA_TX_CP(0)), + cpsw_read_4(sc, CPSW_CPDMA_TX_HDP(0)), txstart, eopi); + /* link the new chain on */ + cpsw_set_txdesc_next(sc, TXDESC_PREV(txstart), + cpsw_txdesc_paddr(sc, txstart)); + if (sc->sc_txeoq) { + /* kick the dma engine */ + sc->sc_txeoq = false; + cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(0), + cpsw_txdesc_paddr(sc, txstart)); + } + } + KERNHIST_LOG(cpswhist, "end txf %x txh %x txn %x txr %x\n", + txfree, sc->sc_txhead, sc->sc_txnext, sc->sc_txrun); +} + +static int +cpsw_ioctl(struct ifnet *ifp, u_long cmd, void *data) +{ + const int s = splnet(); + int error = 0; + + switch (cmd) { + default: + error = ether_ioctl(ifp, cmd, data); + if (error == ENETRESET) { + error = 0; + } + break; + } + + splx(s); + + return error; +} + +static void +cpsw_watchdog(struct ifnet *ifp) +{ + struct cpsw_softc *sc = ifp->if_softc; + + device_printf(sc->sc_dev, "device timeout\n"); + + ifp->if_oerrors++; + cpsw_init(ifp); + cpsw_start(ifp); +} + +static int +cpsw_mii_wait(struct cpsw_softc * const sc, int reg) +{ + u_int tries; + + for (tries = 0; tries < 1000; tries++) { + if ((cpsw_read_4(sc, reg) & __BIT(31)) == 0) + return 0; + delay(1); + } + return ETIMEDOUT; +} + +static int +cpsw_mii_readreg(device_t dev, int phy, int reg) +{ + struct cpsw_softc * const sc = device_private(dev); + uint32_t v; + + if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0) + return 0; + + cpsw_write_4(sc, MDIOUSERACCESS0, (1 << 31) | + ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16)); + + if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0) + return 0; + + v = cpsw_read_4(sc, MDIOUSERACCESS0); + if (v & __BIT(29)) + return v & 0xffff; + else + return 0; +} + +static void +cpsw_mii_writereg(device_t dev, int phy, int reg, int val) +{ + struct cpsw_softc * const sc = device_private(dev); + uint32_t v; + + KASSERT((val & 0xffff0000UL) == 0); + + if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0) + goto out; + + cpsw_write_4(sc, MDIOUSERACCESS0, (1 << 31) | (1 << 30) | + ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16) | val); + + if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0) + goto out; + + v = cpsw_read_4(sc, MDIOUSERACCESS0); + if ((v & __BIT(29)) == 0) +out: + device_printf(sc->sc_dev, "%s error\n", __func__); + +} + +static void +cpsw_mii_statchg(struct ifnet *ifp) +{ + return; +} + +static int +cpsw_new_rxbuf(struct cpsw_softc * const sc, const u_int i) +{ + struct cpsw_ring_data * const rdp = sc->sc_rdp; + const u_int h = RXDESC_PREV(i); + struct cpsw_cpdma_bd bd; + uint32_t * const dw = bd.word; + struct mbuf *m; + int error = ENOBUFS; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + goto reuse; + } + + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + goto reuse; + } + + /* We have a new buffer, prepare it for the ring. */ + + if (rdp->rx_mb[i] != NULL) + bus_dmamap_unload(sc->sc_bdt, rdp->rx_dm[i]); + + m->m_len = m->m_pkthdr.len = MCLBYTES; + + rdp->rx_mb[i] = m; + + error = bus_dmamap_load_mbuf(sc->sc_bdt, rdp->rx_dm[i], rdp->rx_mb[i], + BUS_DMA_READ|BUS_DMA_NOWAIT); + if (error) { + device_printf(sc->sc_dev, "can't load rx DMA map %d: %d\n", + i, error); + } + + bus_dmamap_sync(sc->sc_bdt, rdp->rx_dm[i], + 0, rdp->rx_dm[i]->dm_mapsize, BUS_DMASYNC_PREREAD); + + error = 0; + +reuse: + /* (re-)setup the descriptor */ + dw[0] = 0; + dw[1] = rdp->rx_dm[i]->dm_segs[0].ds_addr; + dw[2] = MIN(0x7ff, rdp->rx_dm[i]->dm_segs[0].ds_len); + dw[3] = CPDMA_BD_OWNER; + + cpsw_set_rxdesc(sc, i, &bd); + /* and link onto ring */ + cpsw_set_rxdesc_next(sc, h, cpsw_rxdesc_paddr(sc, i)); + + return error; +} + +static int +cpsw_init(struct ifnet *ifp) +{ + struct cpsw_softc * const sc = ifp->if_softc; + struct mii_data * const mii = &sc->sc_mii; + int i; + + cpsw_stop(ifp, 0); + + sc->sc_txnext = 0; + sc->sc_txhead = 0; + + /* Reset wrapper */ + cpsw_write_4(sc, CPSW_WR_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_WR_SOFT_RESET) & 1); + + /* Reset SS */ + cpsw_write_4(sc, CPSW_SS_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_SS_SOFT_RESET) & 1); + + /* Clear table and enable ALE */ + cpsw_write_4(sc, CPSW_ALE_CONTROL, + ALECTL_ENABLE_ALE | ALECTL_CLEAR_TABLE); + + /* Reset and init Sliver port 1 and 2 */ + for (i = 0; i < CPSW_ETH_PORTS; i++) { + uint32_t macctl; + + /* Reset */ + cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1); + while(cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1); + /* Set Slave Mapping */ + cpsw_write_4(sc, CPSW_SL_RX_PRI_MAP(i), 0x76543210); + cpsw_write_4(sc, CPSW_PORT_P_TX_PRI_MAP(i+1), 0x33221100); + cpsw_write_4(sc, CPSW_SL_RX_MAXLEN(i), 0x5f2); + /* Set MAC Address */ + cpsw_write_4(sc, CPSW_PORT_P_SA_HI(i+1), + sc->sc_enaddr[0] | (sc->sc_enaddr[1] << 8) | + (sc->sc_enaddr[2] << 16) | (sc->sc_enaddr[3] << 24)); + cpsw_write_4(sc, CPSW_PORT_P_SA_LO(i+1), + sc->sc_enaddr[4] | (sc->sc_enaddr[5] << 8)); + + /* Set MACCONTROL for ports 0,1 */ + macctl = SLMACCTL_FULLDUPLEX | SLMACCTL_GMII_EN | + SLMACCTL_IFCTL_A; + if (sc->sc_phy_has_1000t) + macctl |= SLMACCTL_GIG; + cpsw_write_4(sc, CPSW_SL_MACCONTROL(i), macctl); + + /* Set ALE port to forwarding(3) */ + cpsw_write_4(sc, CPSW_ALE_PORTCTL(i+1), 3); + } + + /* Set Host Port Mapping */ + cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210); + cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0); + + /* Set ALE port to forwarding(3) */ + cpsw_write_4(sc, CPSW_ALE_PORTCTL(0), 3); + + /* Initialize addrs */ + cpsw_ale_update_addresses(sc, 1); + + cpsw_write_4(sc, CPSW_SS_PTYPE, 0); + cpsw_write_4(sc, CPSW_SS_STAT_PORT_EN, 7); + + cpsw_write_4(sc, CPSW_CPDMA_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_CPDMA_SOFT_RESET) & 1); + + for (i = 0; i < 8; i++) { + cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(i), 0); + cpsw_write_4(sc, CPSW_CPDMA_RX_HDP(i), 0); + cpsw_write_4(sc, CPSW_CPDMA_TX_CP(i), 0); + cpsw_write_4(sc, CPSW_CPDMA_RX_CP(i), 0); + } + + bus_space_set_region_4(sc->sc_bst, sc->sc_bsh_txdescs, 0, 0, + CPSW_CPPI_RAM_TXDESCS_SIZE/4); + + sc->sc_txhead = 0; + sc->sc_txnext = 0; + + cpsw_write_4(sc, CPSW_CPDMA_RX_FREEBUFFER(0), 0); + + bus_space_set_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, 0, 0, + CPSW_CPPI_RAM_RXDESCS_SIZE/4); + /* Initialize RX Buffer Descriptors */ + cpsw_set_rxdesc_next(sc, RXDESC_PREV(0), 0); + for (i = 0; i < CPSW_NRXDESCS; i++) { + cpsw_new_rxbuf(sc, i); + } + sc->sc_rxhead = 0; + + /* turn off flow control */ + cpsw_write_4(sc, CPSW_SS_FLOW_CONTROL, 0); + + /* align layer 3 header to 32-bit */ + cpsw_write_4(sc, CPSW_CPDMA_RX_BUFFER_OFFSET, ETHER_ALIGN); + + /* Clear all interrupt Masks */ + cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF); + cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF); + + /* Enable TX & RX DMA */ + cpsw_write_4(sc, CPSW_CPDMA_TX_CONTROL, 1); + cpsw_write_4(sc, CPSW_CPDMA_RX_CONTROL, 1); + + /* Enable TX and RX interrupt receive for core 0 */ + cpsw_write_4(sc, CPSW_WR_C_TX_EN(0), 1); + cpsw_write_4(sc, CPSW_WR_C_RX_EN(0), 1); + cpsw_write_4(sc, CPSW_WR_C_MISC_EN(0), 0x1F); + + /* Enable host Error Interrupt */ + cpsw_write_4(sc, CPSW_CPDMA_DMA_INTMASK_SET, 2); + + /* Enable interrupts for TX and RX Channel 0 */ + cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_SET, 1); + cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_SET, 1); + + /* Ack stalled irqs */ + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RXTH); + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RX); + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_TX); + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_MISC); + + /* Initialize MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */ + /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */ + cpsw_write_4(sc, MDIOCONTROL, + MDIOCTL_ENABLE | MDIOCTL_FAULTENB | MDIOCTL_CLKDIV(0xff)); + + mii_mediachg(mii); + + /* Write channel 0 RX HDP */ + cpsw_write_4(sc, CPSW_CPDMA_RX_HDP(0), cpsw_rxdesc_paddr(sc, 0)); + sc->sc_rxrun = true; + sc->sc_rxeoq = false; + + sc->sc_txrun = true; + sc->sc_txeoq = true; + callout_schedule(&sc->sc_tick_ch, hz); + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + return 0; +} + +static void +cpsw_stop(struct ifnet *ifp, int disable) +{ + struct cpsw_softc * const sc = ifp->if_softc; + struct cpsw_ring_data * const rdp = sc->sc_rdp; + u_int i; + + aprint_debug_dev(sc->sc_dev, "%s: ifp %p disable %d\n", __func__, + ifp, disable); + + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + + callout_stop(&sc->sc_tick_ch); + mii_down(&sc->sc_mii); + + cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_CLEAR, 1); + cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_CLEAR, 1); + cpsw_write_4(sc, CPSW_WR_C_TX_EN(0), 0x0); + cpsw_write_4(sc, CPSW_WR_C_RX_EN(0), 0x0); + cpsw_write_4(sc, CPSW_WR_C_MISC_EN(0), 0x0); + + cpsw_write_4(sc, CPSW_CPDMA_TX_TEARDOWN, 0); + cpsw_write_4(sc, CPSW_CPDMA_RX_TEARDOWN, 0); + i = 0; + while ((sc->sc_txrun || sc->sc_rxrun) && i < 10000) { + delay(10); + if ((sc->sc_txrun == true) && cpsw_txintr(sc) == 0) + sc->sc_txrun = false; + if ((sc->sc_rxrun == true) && cpsw_rxintr(sc) == 0) + sc->sc_rxrun = false; + i++; + } + //printf("%s toredown complete in %u\n", __func__, i); + + /* Reset wrapper */ + cpsw_write_4(sc, CPSW_WR_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_WR_SOFT_RESET) & 1); + + /* Reset SS */ + cpsw_write_4(sc, CPSW_SS_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_SS_SOFT_RESET) & 1); + + for (i = 0; i < CPSW_ETH_PORTS; i++) { + cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1); + while(cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1); + } + + /* Reset CPDMA */ + cpsw_write_4(sc, CPSW_CPDMA_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_CPDMA_SOFT_RESET) & 1); + + /* Release any queued transmit buffers. */ + for (i = 0; i < CPSW_NTXDESCS; i++) { + bus_dmamap_unload(sc->sc_bdt, rdp->tx_dm[i]); + m_freem(rdp->tx_mb[i]); + rdp->tx_mb[i] = NULL; + } + + ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); + ifp->if_timer = 0; + + if (!disable) + return; + + for (i = 0; i < CPSW_NRXDESCS; i++) { + bus_dmamap_unload(sc->sc_bdt, rdp->rx_dm[i]); + m_freem(rdp->rx_mb[i]); + rdp->rx_mb[i] = NULL; + } +} + +static void +cpsw_tick(void *arg) +{ + struct cpsw_softc * const sc = arg; + struct mii_data * const mii = &sc->sc_mii; + const int s = splnet(); + + mii_tick(mii); + + splx(s); + + callout_schedule(&sc->sc_tick_ch, hz); +} + +static int +cpsw_rxthintr(void *arg) +{ + struct cpsw_softc * const sc = arg; + + /* this won't deassert the interrupt though */ + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RXTH); + + return 1; +} + +static int +cpsw_rxintr(void *arg) +{ + struct cpsw_softc * const sc = arg; + struct ifnet * const ifp = &sc->sc_ec.ec_if; + struct cpsw_ring_data * const rdp = sc->sc_rdp; + struct cpsw_cpdma_bd bd; + const uint32_t * const dw = bd.word; + bus_dmamap_t dm; + struct mbuf *m; + u_int i; + u_int len, off; + + KERNHIST_FUNC(__func__); + KERNHIST_CALLED_5(cpswhist, sc, 0, 0, 0); + + for (;;) { + KASSERT(sc->sc_rxhead < CPSW_NRXDESCS); + + i = sc->sc_rxhead; + KERNHIST_LOG(cpswhist, "rxhead %x CP %x\n", i, + cpsw_read_4(sc, CPSW_CPDMA_RX_CP(0)), 0, 0); + dm = rdp->rx_dm[i]; + m = rdp->rx_mb[i]; + + KASSERT(dm != NULL); + KASSERT(m != NULL); + + cpsw_get_rxdesc(sc, i, &bd); + + if (ISSET(dw[3], CPDMA_BD_OWNER)) + break; + + if (ISSET(dw[3], CPDMA_BD_TDOWNCMPLT)) { + sc->sc_rxrun = false; + return 1; + } + + if ((dw[3] & (CPDMA_BD_SOP|CPDMA_BD_EOP)) != + (CPDMA_BD_SOP|CPDMA_BD_EOP)) { + //Debugger(); + } + + bus_dmamap_sync(sc->sc_bdt, dm, 0, dm->dm_mapsize, + BUS_DMASYNC_POSTREAD); + + if (cpsw_new_rxbuf(sc, i) != 0) { + /* drop current packet, reuse buffer for new */ + ifp->if_ierrors++; + goto next; + } + + off = __SHIFTOUT(dw[2], (uint32_t)__BITS(26, 16)); + len = __SHIFTOUT(dw[3], (uint32_t)__BITS(10, 0)); + + if (ISSET(dw[3], CPDMA_BD_PASSCRC)) + len -= ETHER_CRC_LEN; + + m_set_rcvif(m, ifp); + m->m_pkthdr.len = m->m_len = len; + m->m_data += off; + + if_percpuq_enqueue(ifp->if_percpuq, m); + +next: + sc->sc_rxhead = RXDESC_NEXT(sc->sc_rxhead); + if (ISSET(dw[3], CPDMA_BD_EOQ)) { + sc->sc_rxeoq = true; + break; + } else { + sc->sc_rxeoq = false; + } + cpsw_write_4(sc, CPSW_CPDMA_RX_CP(0), + cpsw_rxdesc_paddr(sc, i)); + } + + if (sc->sc_rxeoq) { + device_printf(sc->sc_dev, "rxeoq\n"); + //Debugger(); + } + + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RX); + + return 1; +} + +static int +cpsw_txintr(void *arg) +{ + struct cpsw_softc * const sc = arg; + struct ifnet * const ifp = &sc->sc_ec.ec_if; + struct cpsw_ring_data * const rdp = sc->sc_rdp; + struct cpsw_cpdma_bd bd; + const uint32_t * const dw = bd.word; + bool handled = false; + uint32_t tx0_cp; + u_int cpi; + + KERNHIST_FUNC(__func__); + KERNHIST_CALLED_5(cpswhist, sc, 0, 0, 0); + + KASSERT(sc->sc_txrun); + + KERNHIST_LOG(cpswhist, "before txnext %x txhead %x txrun %x\n", + sc->sc_txnext, sc->sc_txhead, sc->sc_txrun, 0); + + tx0_cp = cpsw_read_4(sc, CPSW_CPDMA_TX_CP(0)); + + if (tx0_cp == 0xfffffffc) { + /* Teardown, ack it */ + cpsw_write_4(sc, CPSW_CPDMA_TX_CP(0), 0xfffffffc); + cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(0), 0); + sc->sc_txrun = false; + return 0; + } + + for (;;) { + tx0_cp = cpsw_read_4(sc, CPSW_CPDMA_TX_CP(0)); + cpi = (tx0_cp - sc->sc_txdescs_pa) / sizeof(struct cpsw_cpdma_bd); + KASSERT(sc->sc_txhead < CPSW_NTXDESCS); + + KERNHIST_LOG(cpswhist, "txnext %x txhead %x txrun %x cpi %x\n", + sc->sc_txnext, sc->sc_txhead, sc->sc_txrun, cpi); + + cpsw_get_txdesc(sc, sc->sc_txhead, &bd); + + if (dw[2] == 0) { + //Debugger(); + } + + if (ISSET(dw[3], CPDMA_BD_SOP) == 0) + goto next; + + if (ISSET(dw[3], CPDMA_BD_OWNER)) { + printf("pwned %x %x %x\n", cpi, sc->sc_txhead, + sc->sc_txnext); + break; + } + + if (ISSET(dw[3], CPDMA_BD_TDOWNCMPLT)) { + sc->sc_txrun = false; + return 1; + } + + bus_dmamap_sync(sc->sc_bdt, rdp->tx_dm[sc->sc_txhead], + 0, rdp->tx_dm[sc->sc_txhead]->dm_mapsize, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_bdt, rdp->tx_dm[sc->sc_txhead]); + + m_freem(rdp->tx_mb[sc->sc_txhead]); + rdp->tx_mb[sc->sc_txhead] = NULL; + + ifp->if_opackets++; + + handled = true; + + ifp->if_flags &= ~IFF_OACTIVE; + +next: + if (ISSET(dw[3], CPDMA_BD_EOP) && ISSET(dw[3], CPDMA_BD_EOQ)) { + sc->sc_txeoq = true; + } + if (sc->sc_txhead == cpi) { + cpsw_write_4(sc, CPSW_CPDMA_TX_CP(0), + cpsw_txdesc_paddr(sc, cpi)); + sc->sc_txhead = TXDESC_NEXT(sc->sc_txhead); + break; + } + sc->sc_txhead = TXDESC_NEXT(sc->sc_txhead); + if (ISSET(dw[3], CPDMA_BD_EOP) && ISSET(dw[3], CPDMA_BD_EOQ)) { + sc->sc_txeoq = true; + break; + } + } + + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_TX); + + if ((sc->sc_txnext != sc->sc_txhead) && sc->sc_txeoq) { + if (cpsw_read_4(sc, CPSW_CPDMA_TX_HDP(0)) == 0) { + sc->sc_txeoq = false; + cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(0), + cpsw_txdesc_paddr(sc, sc->sc_txhead)); + } + } + + KERNHIST_LOG(cpswhist, "after txnext %x txhead %x txrun %x\n", + sc->sc_txnext, sc->sc_txhead, sc->sc_txrun, 0); + KERNHIST_LOG(cpswhist, "CP %x HDP %x\n", + cpsw_read_4(sc, CPSW_CPDMA_TX_CP(0)), + cpsw_read_4(sc, CPSW_CPDMA_TX_HDP(0)), 0, 0); + + if (handled && sc->sc_txnext == sc->sc_txhead) + ifp->if_timer = 0; + + if (handled) + if_schedule_deferred_start(ifp); + + return handled; +} + +static int +cpsw_miscintr(void *arg) +{ + struct cpsw_softc * const sc = arg; + uint32_t miscstat; + uint32_t dmastat; + uint32_t stat; + + miscstat = cpsw_read_4(sc, CPSW_WR_C_MISC_STAT(0)); + device_printf(sc->sc_dev, "%s %x FIRE\n", __func__, miscstat); + +#define CPSW_MISC_HOST_PEND __BIT32(2) +#define CPSW_MISC_STAT_PEND __BIT32(3) + + if (ISSET(miscstat, CPSW_MISC_HOST_PEND)) { + /* Host Error */ + dmastat = cpsw_read_4(sc, CPSW_CPDMA_DMA_INTSTAT_MASKED); + printf("CPSW_CPDMA_DMA_INTSTAT_MASKED %x\n", dmastat); + + printf("rxhead %02x\n", sc->sc_rxhead); + + stat = cpsw_read_4(sc, CPSW_CPDMA_DMASTATUS); + printf("CPSW_CPDMA_DMASTATUS %x\n", stat); + stat = cpsw_read_4(sc, CPSW_CPDMA_TX_HDP(0)); + printf("CPSW_CPDMA_TX0_HDP %x\n", stat); + stat = cpsw_read_4(sc, CPSW_CPDMA_TX_CP(0)); + printf("CPSW_CPDMA_TX0_CP %x\n", stat); + stat = cpsw_read_4(sc, CPSW_CPDMA_RX_HDP(0)); + printf("CPSW_CPDMA_RX0_HDP %x\n", stat); + stat = cpsw_read_4(sc, CPSW_CPDMA_RX_CP(0)); + printf("CPSW_CPDMA_RX0_CP %x\n", stat); + + //Debugger(); + + cpsw_write_4(sc, CPSW_CPDMA_DMA_INTMASK_CLEAR, dmastat); + dmastat = cpsw_read_4(sc, CPSW_CPDMA_DMA_INTSTAT_MASKED); + printf("CPSW_CPDMA_DMA_INTSTAT_MASKED %x\n", dmastat); + } + + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_MISC); + + return 1; +} + +/* + * + * ALE support routines. + * + */ + +static void +cpsw_ale_entry_init(uint32_t *ale_entry) +{ + ale_entry[0] = ale_entry[1] = ale_entry[2] = 0; +} + +static void +cpsw_ale_entry_set_mac(uint32_t *ale_entry, const uint8_t *mac) +{ + ale_entry[0] = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; + ale_entry[1] = mac[0] << 8 | mac[1]; +} + +static void +cpsw_ale_entry_set_bcast_mac(uint32_t *ale_entry) +{ + ale_entry[0] = 0xffffffff; + ale_entry[1] = 0x0000ffff; +} + +static void +cpsw_ale_entry_set(uint32_t *ale_entry, ale_entry_field_t field, uint32_t val) +{ + /* Entry type[61:60] is addr entry(1), Mcast fwd state[63:62] is fw(3)*/ + switch (field) { + case ALE_ENTRY_TYPE: + /* [61:60] */ + ale_entry[1] |= (val & 0x3) << 28; + break; + case ALE_MCAST_FWD_STATE: + /* [63:62] */ + ale_entry[1] |= (val & 0x3) << 30; + break; + case ALE_PORT_MASK: + /* [68:66] */ + ale_entry[2] |= (val & 0x7) << 2; + break; + case ALE_PORT_NUMBER: + /* [67:66] */ + ale_entry[2] |= (val & 0x3) << 2; + break; + default: + panic("Invalid ALE entry field: %d\n", field); + } + + return; +} + +static bool +cpsw_ale_entry_mac_match(const uint32_t *ale_entry, const uint8_t *mac) +{ + return (((ale_entry[1] >> 8) & 0xff) == mac[0]) && + (((ale_entry[1] >> 0) & 0xff) == mac[1]) && + (((ale_entry[0] >>24) & 0xff) == mac[2]) && + (((ale_entry[0] >>16) & 0xff) == mac[3]) && + (((ale_entry[0] >> 8) & 0xff) == mac[4]) && + (((ale_entry[0] >> 0) & 0xff) == mac[5]); +} + +static void +cpsw_ale_set_outgoing_mac(struct cpsw_softc *sc, int port, const uint8_t *mac) +{ + cpsw_write_4(sc, CPSW_PORT_P_SA_HI(port), + mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0]); + cpsw_write_4(sc, CPSW_PORT_P_SA_LO(port), + mac[5] << 8 | mac[4]); +} + +static void +cpsw_ale_read_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry) +{ + cpsw_write_4(sc, CPSW_ALE_TBLCTL, idx & 1023); + ale_entry[0] = cpsw_read_4(sc, CPSW_ALE_TBLW0); + ale_entry[1] = cpsw_read_4(sc, CPSW_ALE_TBLW1); + ale_entry[2] = cpsw_read_4(sc, CPSW_ALE_TBLW2); +} + +static void +cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, + const uint32_t *ale_entry) +{ + cpsw_write_4(sc, CPSW_ALE_TBLW0, ale_entry[0]); + cpsw_write_4(sc, CPSW_ALE_TBLW1, ale_entry[1]); + cpsw_write_4(sc, CPSW_ALE_TBLW2, ale_entry[2]); + cpsw_write_4(sc, CPSW_ALE_TBLCTL, 1 << 31 | (idx & 1023)); +} + +static int +cpsw_ale_remove_all_mc_entries(struct cpsw_softc *sc) +{ + int i; + uint32_t ale_entry[3]; + + /* First two entries are link address and broadcast. */ + for (i = 2; i < CPSW_MAX_ALE_ENTRIES; i++) { + cpsw_ale_read_entry(sc, i, ale_entry); + if (((ale_entry[1] >> 28) & 3) == 1 && /* Address entry */ + ((ale_entry[1] >> 8) & 1) == 1) { /* MCast link addr */ + ale_entry[0] = ale_entry[1] = ale_entry[2] = 0; + cpsw_ale_write_entry(sc, i, ale_entry); + } + } + return CPSW_MAX_ALE_ENTRIES; +} + +static int +cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmask, uint8_t *mac) +{ + int free_index = -1, matching_index = -1, i; + uint32_t ale_entry[3]; + + /* Find a matching entry or a free entry. */ + for (i = 0; i < CPSW_MAX_ALE_ENTRIES; i++) { + cpsw_ale_read_entry(sc, i, ale_entry); + + /* Entry Type[61:60] is 0 for free entry */ + if (free_index < 0 && ((ale_entry[1] >> 28) & 3) == 0) { + free_index = i; + } + + if (cpsw_ale_entry_mac_match(ale_entry, mac)) { + matching_index = i; + break; + } + } + + if (matching_index < 0) { + if (free_index < 0) + return ENOMEM; + i = free_index; + } + + cpsw_ale_entry_init(ale_entry); + + cpsw_ale_entry_set_mac(ale_entry, mac); + cpsw_ale_entry_set(ale_entry, ALE_ENTRY_TYPE, ALE_TYPE_ADDRESS); + cpsw_ale_entry_set(ale_entry, ALE_MCAST_FWD_STATE, ALE_FWSTATE_FWONLY); + cpsw_ale_entry_set(ale_entry, ALE_PORT_MASK, portmask); + + cpsw_ale_write_entry(sc, i, ale_entry); + + return 0; +} + +static int +cpsw_ale_update_addresses(struct cpsw_softc *sc, int purge) +{ + uint8_t *mac = sc->sc_enaddr; + uint32_t ale_entry[3]; + int i; + struct ethercom * const ec = &sc->sc_ec; + struct ether_multi *ifma; + + cpsw_ale_entry_init(ale_entry); + /* Route incoming packets for our MAC address to Port 0 (host). */ + /* For simplicity, keep this entry at table index 0 in the ALE. */ + cpsw_ale_entry_set_mac(ale_entry, mac); + cpsw_ale_entry_set(ale_entry, ALE_ENTRY_TYPE, ALE_TYPE_ADDRESS); + cpsw_ale_entry_set(ale_entry, ALE_PORT_NUMBER, 0); + cpsw_ale_write_entry(sc, 0, ale_entry); + + /* Set outgoing MAC Address for Ports 1 and 2. */ + for (i = CPSW_CPPI_PORTS; i < (CPSW_ETH_PORTS + CPSW_CPPI_PORTS); ++i) + cpsw_ale_set_outgoing_mac(sc, i, mac); + + /* Keep the broadcast address at table entry 1. */ + cpsw_ale_entry_init(ale_entry); + cpsw_ale_entry_set_bcast_mac(ale_entry); + cpsw_ale_entry_set(ale_entry, ALE_ENTRY_TYPE, ALE_TYPE_ADDRESS); + cpsw_ale_entry_set(ale_entry, ALE_MCAST_FWD_STATE, ALE_FWSTATE_FWONLY); + cpsw_ale_entry_set(ale_entry, ALE_PORT_MASK, ALE_PORT_MASK_ALL); + cpsw_ale_write_entry(sc, 1, ale_entry); + + /* SIOCDELMULTI doesn't specify the particular address + being removed, so we have to remove all and rebuild. */ + if (purge) + cpsw_ale_remove_all_mc_entries(sc); + + /* Set other multicast addrs desired. */ + LIST_FOREACH(ifma, &ec->ec_multiaddrs, enm_list) { + cpsw_ale_mc_entry_set(sc, ALE_PORT_MASK_ALL, ifma->enm_addrlo); + } + + return 0; +} Index: src/sys/arch/arm/ti/ti_com.c diff -u /dev/null src/sys/arch/arm/ti/ti_com.c:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/arm/ti/ti_com.c Thu Oct 26 01:16:32 2017 @@ -0,0 +1,169 @@ +/* $NetBSD: ti_com.c,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill <jmcne...@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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> + +__KERNEL_RCSID(1, "$NetBSD: ti_com.c,v 1.1 2017/10/26 01:16:32 jakllsch Exp $"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/device.h> +#include <sys/intr.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/termios.h> + +#include <dev/ic/comvar.h> + +#include <dev/fdt/fdtvar.h> + +static int ti_com_match(device_t, cfdata_t, void *); +static void ti_com_attach(device_t, device_t, void *); + +static const char * const compatible[] = { + "ti,am3352-uart", + "ti,omap3-uart", + NULL +}; + +struct ti_com_softc { + struct com_softc ssc_sc; + void *ssc_ih; + + struct clk *ssc_clk; + struct fdtbus_reset *ssc_rst; +}; + +CFATTACH_DECL_NEW(ti_com, sizeof(struct ti_com_softc), + ti_com_match, ti_com_attach, NULL, NULL); + +static int +ti_com_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +ti_com_attach(device_t parent, device_t self, void *aux) +{ + struct ti_com_softc * const ssc = device_private(self); + struct com_softc * const sc = &ssc->ssc_sc; + struct fdt_attach_args * const faa = aux; + bus_space_handle_t bsh; + bus_space_tag_t bst; + char intrstr[128]; + bus_addr_t addr; + bus_size_t size; + int error; + + if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + bst = faa->faa_a4x_bst; + + sc->sc_dev = self; + + ssc->ssc_clk = fdtbus_clock_get_index(faa->faa_phandle, 0); + ssc->ssc_rst = fdtbus_reset_get_index(faa->faa_phandle, 0); + +#if 0 + if (ssc->ssc_clk == NULL) { + aprint_error(": couldn't get frequency\n"); + return; + } + + sc->sc_frequency = clk_get_rate(ssc->ssc_clk); +#else + sc->sc_frequency = 48000000; +#endif + sc->sc_type = COM_TYPE_NORMAL; + + error = bus_space_map(bst, addr, size, 0, &bsh); + if (error) { + aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error); + return; + } + + COM_INIT_REGS(sc->sc_regs, bst, bsh, addr); + + com_attach_subr(sc); + aprint_naive("\n"); + + if (!fdtbus_intr_str(faa->faa_phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error_dev(self, "failed to decode interrupt\n"); + return; + } + + ssc->ssc_ih = fdtbus_intr_establish(faa->faa_phandle, 0, IPL_SERIAL, + FDT_INTR_MPSAFE, comintr, sc); + if (ssc->ssc_ih == NULL) { + aprint_error_dev(self, "failed to establish interrupt on %s\n", + intrstr); + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); +} + +/* + * Console support + */ + +static int +ti_com_console_match(int phandle) +{ + return of_match_compatible(phandle, compatible); +} + +static void +ti_com_console_consinit(struct fdt_attach_args *faa, u_int uart_freq) +{ + const int phandle = faa->faa_phandle; + bus_space_tag_t bst = faa->faa_a4x_bst; + bus_addr_t addr; + tcflag_t flags; + int speed; + + fdtbus_get_reg(phandle, 0, &addr, NULL); + speed = fdtbus_get_stdout_speed(); + if (speed < 0) + speed = 115200; /* default */ + flags = fdtbus_get_stdout_flags(); + + if (comcnattach(bst, addr, speed, uart_freq, COM_TYPE_NORMAL, flags)) + panic("Cannot initialize ti com console"); +} + +static const struct fdt_console ti_com_console = { + .match = ti_com_console_match, + .consinit = ti_com_console_consinit, +}; + +FDT_CONSOLE(ti_com, &ti_com_console); Index: src/sys/arch/arm/ti/ti_omapintc.c diff -u /dev/null src/sys/arch/arm/ti/ti_omapintc.c:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/arm/ti/ti_omapintc.c Thu Oct 26 01:16:32 2017 @@ -0,0 +1,284 @@ +/* $NetBSD: ti_omapintc.c,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ */ +/* + * Define the SDP2430 specific information and then include the generic OMAP + * interrupt header. + */ + +/* + * 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 this list of conditions + * and the following disclaimer. + * 2. Redistributions in binary form must reproduce this list of conditions + * and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``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 ANY + * 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. + */ + +#define _INTR_PRIVATE + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: ti_omapintc.c,v 1.1 2017/10/26 01:16:32 jakllsch Exp $"); + +#include <sys/param.h> +#include <sys/evcnt.h> +#include <sys/device.h> + +#include <uvm/uvm_extern.h> + +#include <machine/intr.h> +#include <sys/bus.h> + +#include <arm/cpu.h> +#include <arm/armreg.h> +#include <arm/cpufunc.h> +#include <arm/atomic.h> + +#include <dev/fdt/fdtvar.h> + +#define INTC_CONTROL 0x048 +#define INTC_CONTROL_NEWIRQAGR __BIT(0) +#define INTC_ITR 0x080 +#define INTC_MIR 0x084 +#define INTC_MIR_CLEAR 0x088 +#define INTC_MIR_SET 0x08c +#define INTC_PENDING_IRQ 0x098 + +#define INTC_MAX_SOURCES 128 + + +#define INTC_READ(sc, g, o) \ + bus_space_read_4((sc)->sc_memt, (sc)->sc_memh, (g) * 0x20 + (o)) +#define INTC_WRITE(sc, g, o, v) \ + bus_space_write_4((sc)->sc_memt, (sc)->sc_memh, (g) * 0x20 + (o), v) + +static int omap2icu_match(device_t, cfdata_t, void *); +static void omap2icu_attach(device_t, device_t, void *); + +static void omap2icu_unblock_irqs(struct pic_softc *, size_t, uint32_t); +static void omap2icu_block_irqs(struct pic_softc *, size_t, uint32_t); +static void omap2icu_establish_irq(struct pic_softc *, struct intrsource *); +static void omap2icu_set_priority(struct pic_softc *, int); +#if 0 +static void omap2icu_source_name(struct pic_softc *, int, char *, size_t); +#endif + +static const struct pic_ops omap2icu_picops = { + .pic_unblock_irqs = omap2icu_unblock_irqs, + .pic_block_irqs = omap2icu_block_irqs, + .pic_establish_irq = omap2icu_establish_irq, + .pic_set_priority = omap2icu_set_priority, +#if 0 + .pic_source_name = omap2icu_source_name, +#endif +}; + +#define PICTOSOFTC(pic) \ + ((struct omap2icu_softc *)((uintptr_t)(pic) - offsetof(struct omap2icu_softc, sc_pic))) + +struct omap2icu_softc { + device_t sc_dev; + bus_space_tag_t sc_memt; + bus_space_handle_t sc_memh; + struct pic_softc sc_pic; + uint32_t sc_enabled_irqs[howmany(INTC_MAX_SOURCES, 32)]; +}; + +static struct omap2icu_softc *intc_softc; + +static void +omap2icu_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask) +{ + struct omap2icu_softc * const sc = PICTOSOFTC(pic); + const size_t group = irqbase / 32; + KASSERT((irq_mask & sc->sc_enabled_irqs[group]) == 0); + sc->sc_enabled_irqs[group] |= irq_mask; + INTC_WRITE(sc, group, INTC_MIR_CLEAR, irq_mask); + + /* Force INTC to recompute IRQ availability */ + INTC_WRITE(sc, 0, INTC_CONTROL, INTC_CONTROL_NEWIRQAGR); +} + +static void +omap2icu_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask) +{ + struct omap2icu_softc * const sc = PICTOSOFTC(pic); + const size_t group = irqbase / 32; + + INTC_WRITE(sc, group, INTC_MIR_SET, irq_mask); + sc->sc_enabled_irqs[group] &= ~irq_mask; +} + +/* + * Called with interrupts disabled + */ +static int +find_pending_irqs(struct omap2icu_softc *sc, size_t group) +{ + uint32_t pending = INTC_READ(sc, group, INTC_PENDING_IRQ); + + KASSERT((sc->sc_enabled_irqs[group] & pending) == pending); + + if (pending == 0) + return 0; + + return pic_mark_pending_sources(&sc->sc_pic, group * 32, pending); +} + +static void +omap_irq_handler(void *frame) +{ + struct cpu_info * const ci = curcpu(); + struct omap2icu_softc * const sc = intc_softc; + const int oldipl = ci->ci_cpl; + const uint32_t oldipl_mask = __BIT(oldipl); + int ipl_mask = 0; + + ci->ci_data.cpu_nintr++; + + if (sc->sc_enabled_irqs[0]) + ipl_mask |= find_pending_irqs(sc, 0); + if (sc->sc_enabled_irqs[1]) + ipl_mask |= find_pending_irqs(sc, 1); + if (sc->sc_enabled_irqs[2]) + ipl_mask |= find_pending_irqs(sc, 2); + if (sc->sc_enabled_irqs[3]) + ipl_mask |= find_pending_irqs(sc, 3); + + /* force INTC to recomputq IRQ */ + INTC_WRITE(sc, 0, INTC_CONTROL, INTC_CONTROL_NEWIRQAGR); + + /* + * Record the pending_ipls and deliver them if we can. + */ + if ((ipl_mask & ~oldipl_mask) > oldipl_mask) + pic_do_pending_ints(I32_bit, oldipl, frame); +} + +void +omap2icu_establish_irq(struct pic_softc *pic, struct intrsource *is) +{ + KASSERT(is->is_irq < PICTOSOFTC(pic)->sc_pic.pic_maxsources); + KASSERT(is->is_type == IST_LEVEL); +} + +static void +omap2icu_set_priority(struct pic_softc *pic, int ipl) +{ + curcpu()->ci_cpl = ipl; +} + +static void * +omapintc_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags, + int (*func)(void *), void *arg) +{ + const u_int irq = be32toh(specifier[0]); + if (irq >= INTC_MAX_SOURCES) { + device_printf(dev, "IRQ %u is invalid\n", irq); + return NULL; + } + + const u_int mpsafe = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0; + return intr_establish(irq, ipl, IST_LEVEL | mpsafe, func, arg); +} + +static void +omapintc_fdt_disestablish(device_t dev, void *ih) +{ + intr_disestablish(ih); +} + +static bool +omapintc_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen) +{ + if (!specifier) + return false; + + const u_int irq = be32toh(specifier[0]); + snprintf(buf, buflen, "INTC irq %d", irq); + return true; +} + +static const struct fdtbus_interrupt_controller_func omapintc_fdt_funcs = { + .establish = omapintc_fdt_establish, + .disestablish = omapintc_fdt_disestablish, + .intrstr = omapintc_fdt_intrstr, +}; + +int +omap2icu_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + static const char * const compatible[] = { + "ti,am33xx-intc", + NULL + }; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +void +omap2icu_attach(device_t parent, device_t self, void *aux) +{ + struct omap2icu_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + bus_addr_t addr; + bus_size_t size; + int error; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + sc->sc_dev = self; + sc->sc_memt = faa->faa_bst; + if (bus_space_map(sc->sc_memt, addr, size, 0, &sc->sc_memh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal("\n"); + + INTC_WRITE(sc, 0, INTC_MIR_SET, 0xffffffff); + INTC_WRITE(sc, 1, INTC_MIR_SET, 0xffffffff); + INTC_WRITE(sc, 2, INTC_MIR_SET, 0xffffffff); + + sc->sc_dev = self; + self->dv_private = sc; + + sc->sc_pic.pic_ops = &omap2icu_picops; + sc->sc_pic.pic_maxsources = INTC_MAX_SOURCES; + snprintf(sc->sc_pic.pic_name, sizeof(sc->sc_pic.pic_name), "intc"); + pic_add(&sc->sc_pic, 0); + error = fdtbus_register_interrupt_controller(self, phandle, + &omapintc_fdt_funcs); + if (error) { + aprint_error_dev(self, "couldn't register with fdtbus: %d\n", + error); + return; + } + + KASSERT(intc_softc == NULL); + intc_softc = sc; + arm_fdt_irq_set_handler(omap_irq_handler); +} + +CFATTACH_DECL_NEW(omapintc, + sizeof(struct omap2icu_softc), + omap2icu_match, omap2icu_attach, + NULL, NULL); Index: src/sys/arch/arm/ti/ti_omaptimer.c diff -u /dev/null src/sys/arch/arm/ti/ti_omaptimer.c:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/arm/ti/ti_omaptimer.c Thu Oct 26 01:16:32 2017 @@ -0,0 +1,122 @@ +/* $NetBSD: ti_omaptimer.c,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: ti_omaptimer.c,v 1.1 2017/10/26 01:16:32 jakllsch Exp $"); + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/device.h> +#include <sys/timetc.h> +#include <sys/kernel.h> + +#include <arm/locore.h> +#include <arm/fdt/arm_fdtvar.h> + +#include <dev/fdt/fdtvar.h> + +static const char * const compatible[] = { + "ti,am335x-timer-1ms", + "ti,am335x-timer", + NULL +}; + +struct omaptimer_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + int sc_phandle; + struct clk *sc_clk; + struct timecounter sc_tc; +}; + +static struct omaptimer_softc *timer_softc; + +static int +omaptimer_intr(void *arg) +{ + struct omaptimer_softc * const sc = timer_softc; + struct clockframe * const frame = arg; + + bus_space_write_4(sc->sc_bst, sc->sc_bsh, 0x28, 2); + hardclock(frame); + + return 1; +} + +static void +omaptimer_cpu_initclocks(void) +{ + struct omaptimer_softc * const sc = timer_softc; + char intrstr[128]; + void *ih; + + KASSERT(sc != NULL); + if (!fdtbus_intr_str(sc->sc_phandle, 0, intrstr, sizeof(intrstr))) + panic("%s: failed to decode interrupt", __func__); + ih = fdtbus_intr_establish(sc->sc_phandle, 0, IPL_CLOCK, + FDT_INTR_MPSAFE, omaptimer_intr, NULL); + if (ih == NULL) + panic("%s: failed to establish timer interrupt", __func__); + + aprint_normal_dev(sc->sc_dev, "interrupting on %s\n", intrstr); + + uint32_t value; + value = (0xffffffff - ((24000000UL / hz) - 1)); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, 0x40, value); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, 0x3c, value); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, 0x2c, 2); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, 0x38, 3); +} + +static int +omaptimer_match(device_t parent, cfdata_t match, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +omaptimer_attach(device_t parent, device_t self, void *aux) +{ + struct omaptimer_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + bus_addr_t addr; + bus_size_t size; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + +#if 0 + if ((sc->sc_clk = fdtbus_clock_get_index(phandle, 0)) == NULL) { + aprint_error(": couldn't get clock\n"); + return; + } +#endif + + sc->sc_dev = self; + sc->sc_phandle = phandle; + sc->sc_bst = faa->faa_bst; + + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + device_printf(self, "unable to map bus space"); + return; + } + + aprint_naive("\n"); + aprint_normal(": Timer\n"); + + /* Use this as the OS timer in UP configurations */ + if (!arm_has_mpext_p && addr == 0x48042000) { /* TIMER3 */ + timer_softc = sc; + arm_fdt_timer_register(omaptimer_cpu_initclocks); + } +} + +CFATTACH_DECL_NEW(omaptimer, sizeof(struct omaptimer_softc), + omaptimer_match, omaptimer_attach, NULL, NULL); + Index: src/sys/arch/arm/ti/ti_platform.c diff -u /dev/null src/sys/arch/arm/ti/ti_platform.c:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/arm/ti/ti_platform.c Thu Oct 26 01:16:32 2017 @@ -0,0 +1,155 @@ +/* $NetBSD: ti_platform.c,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ */ + +#include "opt_fdt_arm.h" + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: ti_platform.c,v 1.1 2017/10/26 01:16:32 jakllsch Exp $"); + +#include <sys/param.h> + +#include <dev/fdt/fdtvar.h> +#include <arm/fdt/arm_fdtvar.h> + +#include <uvm/uvm_extern.h> + +#include <dev/ic/comreg.h> + +#define DEVMAP_ALIGN(a) ((a) & ~L1_S_OFFSET) +#define DEVMAP_SIZE(s) roundup2((s), L1_S_SIZE) +#define DEVMAP_ENTRY(va, pa, sz) \ + { \ + .pd_va = DEVMAP_ALIGN(va), \ + .pd_pa = DEVMAP_ALIGN(pa), \ + .pd_size = DEVMAP_SIZE(sz), \ + .pd_prot = VM_PROT_READ|VM_PROT_WRITE, \ + .pd_cache = PTE_NOCACHE \ + } +#define DEVMAP_ENTRY_END { 0 } + +extern struct bus_space armv7_generic_bs_tag; +extern struct bus_space armv7_generic_a4x_bs_tag; +extern struct arm32_bus_dma_tag armv7_generic_dma_tag; + +static const struct pmap_devmap * +am33xx_platform_devmap(void) +{ + static const struct pmap_devmap devmap[] = { + DEVMAP_ENTRY(0xe4c00000, 0x44c00000, 0x00400000), + DEVMAP_ENTRY(0xe8000000, 0x48000000, 0x01000000), + DEVMAP_ENTRY(0xea000000, 0x4a000000, 0x01000000), + DEVMAP_ENTRY_END + }; + + return devmap; +} + +static void +am33xx_platform_init_attach_args(struct fdt_attach_args *faa) +{ + faa->faa_bst = &armv7_generic_bs_tag; + faa->faa_a4x_bst = &armv7_generic_a4x_bs_tag; + faa->faa_dmat = &armv7_generic_dma_tag; +} + +static void +am33xx_platform_early_putchar(char c) +{ +#ifdef CONSADDR +#define CONSADDR_VA ((CONSADDR - 0x44c00000) + 0xe4c00000) + volatile uint32_t *uartaddr = (volatile uint32_t *)CONSADDR_VA; + + while ((le32toh(uartaddr[com_lsr]) & LSR_TXRDY) == 0) + ; + + uartaddr[com_data] = htole32(c); +#endif +} + +static void +wdelay(bus_space_tag_t bst, bus_space_handle_t bsh) +{ + while (bus_space_read_4(bst, bsh, 0x34) != 0) + delay(10); +} + +static void +am33xx_platform_bootstrap(void) +{ + static bus_space_tag_t bst = &armv7_generic_bs_tag; + static bus_space_handle_t bsh; + + bus_space_map(bst, 0x44e00000, 0x1000, 0, &bsh); + bus_space_write_4(bst, bsh, 0x508, 0x1); /* CLKSEL_TIMER2_CLK: CLK_M_OSC */ + bus_space_write_4(bst, bsh, 0x50c, 0x1); /* CLKSEL_TIMER3_CLK: CLK_M_OSC */ + bus_space_write_4(bst, bsh, 0x80, 0x2); /* CM_PER_TIMER2_CLKCTRL: MODULEMODE: ENABLE */ + bus_space_write_4(bst, bsh, 0x84, 0x2); /* CM_PER_TIMER3_CLKCTRL: MODULEMODE: ENABLE */ + bus_space_unmap(bst, bsh, 0x1000); + + bus_space_map(bst, 0x48040000, 0x1000, 0, &bsh); /* TIMER2 for delay() */ + + bus_space_write_4(bst, bsh, 0x40, 0); /* Load */ + bus_space_write_4(bst, bsh, 0x3c, 0); /* Counter */ + bus_space_write_4(bst, bsh, 0x38, 3); /* Control */ + + bus_space_unmap(bst, bsh, 0x1000); + + bus_space_map(bst, 0x44e35000, 0x1000, 0, &bsh); + wdelay(bst, bsh); + bus_space_write_4(bst, bsh, 0x48, 0xAAAA); + wdelay(bst, bsh); + bus_space_write_4(bst, bsh, 0x48, 0x5555); + wdelay(bst, bsh); + bus_space_unmap(bst, bsh, 0x1000); + + bus_space_map(bst, 0x44e00000, 0x1000, 0, &bsh); + bus_space_write_4(bst, bsh, 0x4d4, 0); /* suspend watch dog */ + bus_space_unmap(bst, bsh, 0x1000); +} + +static u_int +am33xx_platform_uart_freq(void) +{ + return 48000000; +} + +static void +am33xx_platform_delay(u_int n) +{ + static bus_space_tag_t bst = &armv7_generic_bs_tag; + static bus_space_handle_t bsh = 0; + + uint32_t cur, prev; + long ticks = n * 24; + + if (bsh == 0) + bus_space_map(bst, 0x48040000, 0x1000, 0, &bsh); /* TIMER2 */ + + prev = bus_space_read_4(bst, bsh, 0x3c); + while (ticks > 0) { + cur = bus_space_read_4(bst, bsh, 0x3c); + if (cur > prev) + ticks -= (cur - prev); + else + ticks -= (UINT32_MAX - prev + 1 - cur); + prev = cur; + } +} + +static const struct arm_platform am33xx_platform = { + .devmap = am33xx_platform_devmap, + .init_attach_args = am33xx_platform_init_attach_args, + .early_putchar = am33xx_platform_early_putchar, + .bootstrap = am33xx_platform_bootstrap, + .uart_freq = am33xx_platform_uart_freq, + .delay = am33xx_platform_delay, +}; + +void dummysetstatclockrate(int); +void +dummysetstatclockrate(int newhz) +{ +} +__weak_alias(setstatclockrate, dummysetstatclockrate); + +ARM_PLATFORM(am33xx, "ti,am33xx", &am33xx_platform); + Index: src/sys/arch/arm/ti/ti_platform.h diff -u /dev/null src/sys/arch/arm/ti/ti_platform.h:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/arm/ti/ti_platform.h Thu Oct 26 01:16:32 2017 @@ -0,0 +1,8 @@ +#ifndef _ARM_TI_TI_PLATFORM_H_ +#define _ARM_TI_TI_PLATFORM_H_ + +#define TI_CORE_VBASE 0xe4c00000 +#define TI_CORE_PBASE 0x44c00000 +#define TI_CORE_SIZE 0x00400000 + +#endif /* _ARM_TI_TI_PLATFORM_H_ */ Index: src/sys/arch/evbarm/conf/TI diff -u /dev/null src/sys/arch/evbarm/conf/TI:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/evbarm/conf/TI Thu Oct 26 01:16:32 2017 @@ -0,0 +1,48 @@ +# $NetBSD: TI,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ +# + +include "arch/evbarm/conf/std.ti" +include "arch/evbarm/conf/GENERIC.common" + +options VERBOSE_INIT_ARM +options CONSADDR=0x44e09000 + +makeoptions DTS=" + am335x-bone.dts + am335x-boneblack.dts + am335x-boneblack-wireless.dts + am335x-bonegreen.dts + am335x-bonegreen-wireless.dts +" + +makeoptions DEBUG="-g" # compile full symbol table +makeoptions COPY_SYMTAB=1 + +#options DIAGNOSTIC +#options DEBUG +options LOCKDEBUG + +options CPU_CORTEXA8 + +options OMAP_SYSTEM_CLOCK_FREQ="48000000UL" + +config netbsd root on ? type ? + +armfdt0 at root +fdt* at fdtbus? + +cpus* at fdt? pass 0 +cpu* at cpus? + +com* at fdt? + +omapintc* at fdt? pass 1 +omaptimer* at fdt? + +fregulator* at fdt? +gpioleds* at fdt? + +cpsw* at fdt? +ukphy* at mii? + +cinclude "arch/evbarm/conf/TI.local" Index: src/sys/arch/evbarm/conf/files.ti diff -u /dev/null src/sys/arch/evbarm/conf/files.ti:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/evbarm/conf/files.ti Thu Oct 26 01:16:32 2017 @@ -0,0 +1,6 @@ +# $NetBSD: files.ti,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ +# + +include "arch/evbarm/conf/files.fdt" + +include "arch/arm/ti/files.ti" Index: src/sys/arch/evbarm/conf/mk.ti diff -u /dev/null src/sys/arch/evbarm/conf/mk.ti:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/evbarm/conf/mk.ti Thu Oct 26 01:16:32 2017 @@ -0,0 +1,36 @@ +# $NetBSD: mk.ti,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ + +.if !empty(MACHINE_ARCH:M*eb) +EXTRA_LINKFLAGS+= --be8 +.endif + +CPPFLAGS+= -mcpu=cortex-a8 +CPPFLAGS+= -mfpu=neon + +SYSTEM_FIRST_OBJ= ti_start.o +SYSTEM_FIRST_SFILE= ${THISARM}/ti/ti_start.S + +GENASSYM_EXTRAS+= ${THISARM}/beagle/genassym.cf + +_OSRELEASE!= ${HOST_SH} $S/conf/osrelease.sh + +MKUBOOTIMAGEARGS= -A arm -T kernel -O linux +MKUBOOTIMAGEARGS+= -a $(KERNEL_BASE_PHYS) -e $(KERNEL_BASE_PHYS) +MKUBOOTIMAGEARGS+= -n "NetBSD/$(BOARDTYPE) ${_OSRELEASE}" +MKUBOOTIMAGEARGS_NONE= ${MKUBOOTIMAGEARGS} -C none +MKUBOOTIMAGEARGS_GZ= ${MKUBOOTIMAGEARGS} -C gz + +SYSTEM_LD_TAIL_EXTRA+=; \ + echo ${OBJCOPY} -S -O binary $@ $@.bin; \ + ${OBJCOPY} -S -O binary $@ $@.bin; \ + echo ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_NONE} $@.bin $@.ub; \ + ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_NONE} $@.bin $@.ub; \ + echo ${TOOL_GZIP} -c $@.bin > $@.bin.gz; \ + ${TOOL_GZIP} -c $@.bin > $@.bin.gz; \ + echo ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_GZ} $@.bin.gz $@.gz.ub; \ + ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_GZ} $@.bin.gz $@.gz.ub + +EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.bin@} +EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.ub@} +EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.bin.gz@} +EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.gz.ub@} Index: src/sys/arch/evbarm/conf/std.ti diff -u /dev/null src/sys/arch/evbarm/conf/std.ti:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/evbarm/conf/std.ti Thu Oct 26 01:16:32 2017 @@ -0,0 +1,31 @@ +# $NetBSD: std.ti,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ +# + +machine evbarm arm +include "arch/evbarm/conf/std.evbarm" + +include "arch/evbarm/conf/files.ti" + + +options FDT +options DRAM_BLOCKS=256 +options __HAVE_CPU_COUNTER +options __HAVE_FAST_SOFTINTS +options __HAVE_CPU_UAREA_ALLOC_IDLELWP +options ARM_HAS_VBAR +options __HAVE_MM_MD_DIRECT_MAPPED_PHYS +options TPIDRPRW_IS_CURCPU +options KERNEL_BASE_EXT=0x80000000 +options FPU_VFP +options __BUS_SPACE_HAS_STREAM_METHODS +options __HAVE_GENERIC_CPU_INITCLOCKS + +options LOADADDRESS="0x80008000" +makeoptions KERNEL_BASE_PHYS="0x80008000" +makeoptions KERNEL_BASE_VIRT="0x80008000" +makeoptions BOARDTYPE="TI" +makeoptions BOARDMKFRAG="${THISARM}/conf/mk.ti" +makeoptions CPUFLAGS="-march=armv7-a -mfpu=neon" + +options ARM_INTR_IMPL="<arch/arm/fdt/fdt_intr.h>" +options ARM_GENERIC_TODR Index: src/sys/arch/evbarm/ti/genassym.cf diff -u /dev/null src/sys/arch/evbarm/ti/genassym.cf:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/evbarm/ti/genassym.cf Thu Oct 26 01:16:32 2017 @@ -0,0 +1,38 @@ +# $NetBSD: genassym.cf,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ + +#- +# Copyright (c) 2013 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Matt Thomas of 3am Software Foundry. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +include <dev/ic/ns16550reg.h> +include <dev/ic/comreg.h> + +define LSR_TXRDY LSR_TXRDY +define LSR_TSRE LSR_TSRE +define COM_DATA com_data +define COM_LSR com_lsr Index: src/sys/arch/evbarm/ti/ti_start.S diff -u /dev/null src/sys/arch/evbarm/ti/ti_start.S:1.1 --- /dev/null Thu Oct 26 01:16:33 2017 +++ src/sys/arch/evbarm/ti/ti_start.S Thu Oct 26 01:16:32 2017 @@ -0,0 +1,196 @@ +/* $NetBSD: ti_start.S,v 1.1 2017/10/26 01:16:32 jakllsch Exp $ */ + +/*- + * Copyright (c) 2014, 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas of 3am Software Foundry. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include "opt_cpuoptions.h" +#include "opt_cputypes.h" +#include "opt_multiprocessor.h" +#include "opt_arm_debug.h" +#include "opt_fdt_arm.h" + +#include <arm/asm.h> +#include <arm/armreg.h> +#include "assym.h" + +#include <arch/arm/ti/ti_platform.h> + +RCSID("$NetBSD: ti_start.S,v 1.1 2017/10/26 01:16:32 jakllsch Exp $") + +#if defined(VERBOSE_INIT_ARM) && defined(CONSADDR) +#define XPUTC(n) mov r0, n; bl xputc +#if KERNEL_BASE_VOFFSET == 0 +#define XPUTC2(n) mov r0, n; bl xputc +#else +#define XPUTC2(n) mov r0, n; blx r11 +#endif +#ifdef __ARMEB__ +#define COM_BSWAP +#endif +#define COM_MULT 4 +#define XPUTC_COM 1 +#else +#define XPUTC(n) +#define XPUTC2(n) +#endif + +#define INIT_MEMSIZE 64 +#define TEMP_L1_TABLE (KERNEL_BASE - KERNEL_BASE_VOFFSET + INIT_MEMSIZE * L1_S_SIZE - L1_TABLE_SIZE) + +#define MD_CPU_HATCH _C_LABEL(arm_fdt_cpu_hatch) + +/* + * Kernel start routine for TI SoCs + * At this point, this code has been loaded into SDRAM + * and the MMU maybe on or maybe off. + */ +#ifdef KERNEL_BASES_EQUAL + .text +#else + .section .start,"ax",%progbits +#endif + + .global _C_LABEL(ti_start) +_C_LABEL(ti_start): +#ifdef __ARMEB__ + setend be /* force big endian */ +#endif + mov r9, #0 + + /* Move into supervisor mode and disable IRQs/FIQs. */ + cpsid if, #PSR_SVC32_MODE + + /* + * Save any arguments passed to us. + */ + movw r4, #:lower16:uboot_args + movt r4, #:upper16:uboot_args + sub r4, r4, #KERNEL_BASE_VOFFSET + + stmia r4, {r0-r3} // Save the arguments + + /* Add DTB PA (1MB) from r2 to MMU init table */ + movw r3, #:lower16:(L1_S_SIZE - 1) /* align DTB PA to 1M */ + movt r3, #:upper16:(L1_S_SIZE - 1) + bic r0, r2, r3 + orr r0, r0, #1 /* 1MB mapping */ + bic r1, r2, r3 + movw r3, #:lower16:(L1_S_PROTO_armv7|L1_S_APv7_KRW|L1_S_CACHEABLE) + movt r3, #:upper16:(L1_S_PROTO_armv7|L1_S_APv7_KRW|L1_S_CACHEABLE) + orr r1, r1, r3 + adr r3, .Lmmu_init_table_dtb /* table entry addr */ + stmia r3, {r0-r1} /* patch table entry */ + + /* + * Turn on the SMP bit + */ + bl cortex_init + + /* + * Set up a preliminary mapping in the MMU to allow us to run + * at KERNEL_BASE with caches on. + */ + movw r0, #:lower16:TEMP_L1_TABLE + movt r0, #:upper16:TEMP_L1_TABLE + movw r1, #:lower16:.Lmmu_init_table + movt r1, #:upper16:.Lmmu_init_table + bl arm_boot_l1pt_init + XPUTC(#'D') + + /* + * Turn on the MMU, Caches, etc. Return to new enabled address space. + */ + movw r0, #:lower16:TEMP_L1_TABLE + movt r0, #:upper16:TEMP_L1_TABLE +#if KERNEL_BASE_VOFFSET == 0 + bl arm_cpuinit +#else + /* + * After the MMU is on, we can execute in the normal .text segment + * so setup the lr to be in .text. Cache the address for xputc + * before we go. + */ +#if defined(VERBOSE_INIT_ARM) + adr r11, xputc @ for XPUTC2 +#endif + movw lr, #:lower16:1f + movt lr, #:upper16:1f + b arm_cpuinit + .pushsection .text,"ax",%progbits +1: +#endif + XPUTC2(#'Z') + + /* + * Jump to start in locore.S, which in turn will call initarm and main. + */ + b start + + /* NOTREACHED */ + +#ifndef KERNEL_BASES_EQUAL + .popsection +#endif + +#include <arm/cortex/a9_mpsubr.S> + +.Lmmu_init_table: + MMU_INIT(KERNEL_BASE, KERNEL_BASE - KERNEL_BASE_VOFFSET, INIT_MEMSIZE, + L1_S_PROTO_armv7 | L1_S_APv7_KRW | L1_S_CACHEABLE) + +#if KERNEL_BASE_VOFFSET != 0 + /* Map KERNEL_BASE VA to SDRAM PA, write-back cacheable, shareable */ + MMU_INIT(KERNEL_BASE - KERNEL_BASE_VOFFSET, + KERNEL_BASE - KERNEL_BASE_VOFFSET, INIT_MEMSIZE, + L1_S_PROTO_armv7 | L1_S_APv7_KRW | L1_S_CACHEABLE) +#endif + + /* Map CORE */ + MMU_INIT(TI_CORE_VBASE, TI_CORE_PBASE, + (TI_CORE_SIZE + L1_S_SIZE - 1) / L1_S_SIZE, + L1_S_PROTO_armv7 | L1_S_APv7_KRW | L1_S_V6_XN) + + /* Map CORE */ + MMU_INIT(TI_CORE_PBASE, TI_CORE_PBASE, + (TI_CORE_SIZE + L1_S_SIZE - 1) / L1_S_SIZE, + L1_S_PROTO_armv7 | L1_S_APv7_KRW | L1_S_V6_XN) + + /* Map CORE */ + MMU_INIT(0xe8000000, 0x48000000, + (0x01000000 + L1_S_SIZE - 1) / L1_S_SIZE, + L1_S_PROTO_armv7 | L1_S_APv7_KRW | L1_S_V6_XN) + +.Lmmu_init_table_dtb: + /* Map DTB from bootloader (patched in later) */ + MMU_INIT(0, 0, 0, 0) + + /* end of table */ + MMU_INIT(0, 0, 0, 0) + +END(_C_LABEL(ti_start))