Index: head/sys/arm/conf/RT1310 =================================================================== --- head/sys/arm/conf/RT1310 (nonexistent) +++ head/sys/arm/conf/RT1310 (revision 317872) @@ -0,0 +1,80 @@ +# +# Custom kernel for RT1310 boards. +# +# $FreeBSD$ +# + +ident RT1310 +include "std.arm" +hints "RT1310.hints" + +# Flattened Device Tree +options FDT +options FDT_DTB_STATIC +makeoptions FDT_DTS_FILE=wzr2-g300n.dts + +makeoptions MODULES_OVERRIDE="" + +#makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols +makeoptions WERROR="-Werror" + +options SCHED_4BSD # 4BSD scheduler +options INET # InterNETworking +options FFS # Berkeley Fast Filesystem +options TMPFS # Efficient memory filesystem +options MSDOSFS + +options ROOTDEVNAME=\"cd9660:/dev/cfid0s.rootfs.uzip\" + +options SYSVSHM # SYSV-style shared memory +options SYSVMSG # SYSV-style message queues +options SYSVSEM # SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions +options MUTEX_NOINLINE +options RWLOCK_NOINLINE +options NO_FFS_SNAPSHOT +options NO_SWAPPING + +# Debugging +options ALT_BREAK_TO_DEBUGGER +options DDB +#options DEADLKRES # Enable the deadlock resolver +#options DIAGNOSTIC +#options INVARIANTS # Enable calls of extra sanity checking +#options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS +options KDB +options WITNESS # Enable checks to detect deadlocks and cycles +options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed +#options WITNESS_KDB + +# Pseudo devices +device loop +device md +device pty +device random + +# Serial ports +device uart +device uart_ns8250 + +# Flash +device cfi +device cfid + +# Networking +device ether +device mii +device bpf +device fv + +# etherswitch +device mdio +device etherswitch +device miiproxy +device ip17x + +# GPIO +device gpio +device gpioled +device rt1310gpio + Property changes on: head/sys/arm/conf/RT1310 ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/sys/arm/ralink/files.ralink =================================================================== --- head/sys/arm/ralink/files.ralink (nonexistent) +++ head/sys/arm/ralink/files.ralink (revision 317872) @@ -0,0 +1,9 @@ +# $FreeBSD$ +arm/ralink/rt1310_machdep.c standard +arm/ralink/rt1310_intc.c standard +arm/ralink/rt1310_gpio.c optional rt1310gpio +arm/ralink/rt1310_timer.c standard +arm/ralink/if_fv.c optional fv + +kern/kern_clocksource.c standard + Property changes on: head/sys/arm/ralink/files.ralink ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/sys/arm/ralink/if_fv.c =================================================================== --- head/sys/arm/ralink/if_fv.c (nonexistent) +++ head/sys/arm/ralink/if_fv.c (revision 317872) @@ -0,0 +1,1873 @@ +/*- + * Copyright (c) 2016 Hiroki Mori. All rights reserved. + * Copyright (C) 2007 + * Oleksandr Tymoshenko . 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 SOFTWFV IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE FV DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES 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 MIND, 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 SOFTWFV, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: $ + * + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * FV Ethernet interface driver + * copy from mips/idt/if_kr.c and netbsd code + */ +#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 +#include + +#include +#include + +/* Todo: move to options.arm */ +/*#define FV_MDIO*/ + +#ifdef FV_MDIO +#include +#include +#include "mdio_if.h" +#endif + +MODULE_DEPEND(are, ether, 1, 1, 1); +MODULE_DEPEND(are, miibus, 1, 1, 1); +#ifdef FV_MDIO +MODULE_DEPEND(are, mdio, 1, 1, 1); +#endif + +#include "miibus_if.h" + +#include + +#ifdef FV_DEBUG +void dump_txdesc(struct fv_softc *, int); +void dump_status_reg(struct fv_softc *); +#endif + +static int fv_attach(device_t); +static int fv_detach(device_t); +static int fv_ifmedia_upd(struct ifnet *); +static void fv_ifmedia_sts(struct ifnet *, struct ifmediareq *); +static int fv_ioctl(struct ifnet *, u_long, caddr_t); +static void fv_init(void *); +static void fv_init_locked(struct fv_softc *); +static void fv_link_task(void *, int); +static int fv_miibus_readreg(device_t, int, int); +static void fv_miibus_statchg(device_t); +static int fv_miibus_writereg(device_t, int, int, int); +static int fv_probe(device_t); +static void fv_reset(struct fv_softc *); +static int fv_resume(device_t); +static int fv_rx_ring_init(struct fv_softc *); +static int fv_tx_ring_init(struct fv_softc *); +static int fv_shutdown(device_t); +static void fv_start(struct ifnet *); +static void fv_start_locked(struct ifnet *); +static void fv_stop(struct fv_softc *); +static int fv_suspend(device_t); + +static void fv_rx(struct fv_softc *); +static void fv_tx(struct fv_softc *); +static void fv_intr(void *); +static void fv_tick(void *); + +static void fv_dmamap_cb(void *, bus_dma_segment_t *, int, int); +static int fv_dma_alloc(struct fv_softc *); +static void fv_dma_free(struct fv_softc *); +static int fv_newbuf(struct fv_softc *, int); +static __inline void fv_fixup_rx(struct mbuf *); + +static void fv_hinted_child(device_t bus, const char *dname, int dunit); + +static void fv_setfilt(struct fv_softc *sc); + +static device_method_t fv_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, fv_probe), + DEVMETHOD(device_attach, fv_attach), + DEVMETHOD(device_detach, fv_detach), + DEVMETHOD(device_suspend, fv_suspend), + DEVMETHOD(device_resume, fv_resume), + DEVMETHOD(device_shutdown, fv_shutdown), + + /* MII interface */ + DEVMETHOD(miibus_readreg, fv_miibus_readreg), + DEVMETHOD(miibus_writereg, fv_miibus_writereg), +#if !defined(FV_MDIO) + DEVMETHOD(miibus_statchg, fv_miibus_statchg), +#endif + + /* bus interface */ + DEVMETHOD(bus_add_child, device_add_child_ordered), + DEVMETHOD(bus_hinted_child, fv_hinted_child), + + DEVMETHOD_END +}; + +static driver_t fv_driver = { + "fv", + fv_methods, + sizeof(struct fv_softc) +}; + +static devclass_t fv_devclass; + +DRIVER_MODULE(fv, simplebus, fv_driver, fv_devclass, 0, 0); +#ifdef MII +DRIVER_MODULE(miibus, fv, miibus_driver, miibus_devclass, 0, 0); +#endif + +static struct mtx miibus_mtx; +MTX_SYSINIT(miibus_mtx, &miibus_mtx, "are mii lock", MTX_DEF); + +#ifdef FV_MDIO +static int fvmdio_probe(device_t); +static int fvmdio_attach(device_t); +static int fvmdio_detach(device_t); + +/* + * Declare an additional, separate driver for accessing the MDIO bus. + */ +static device_method_t fvmdio_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, fvmdio_probe), + DEVMETHOD(device_attach, fvmdio_attach), + DEVMETHOD(device_detach, fvmdio_detach), + + /* bus interface */ + DEVMETHOD(bus_add_child, device_add_child_ordered), + + /* MDIO access */ + DEVMETHOD(mdio_readreg, fv_miibus_readreg), + DEVMETHOD(mdio_writereg, fv_miibus_writereg), +}; + +DEFINE_CLASS_0(fvmdio, fvmdio_driver, fvmdio_methods, + sizeof(struct fv_softc)); +static devclass_t fvmdio_devclass; + +DRIVER_MODULE(miiproxy, fv, miiproxy_driver, miiproxy_devclass, 0, 0); +DRIVER_MODULE(fvmdio, simplebus, fvmdio_driver, fvmdio_devclass, 0, 0); +DRIVER_MODULE(mdio, fvmdio, mdio_driver, mdio_devclass, 0, 0); +#endif + +/* setup frame code refer dc code */ + +static void +fv_setfilt(struct fv_softc *sc) +{ + uint16_t eaddr[(ETHER_ADDR_LEN+1)/2]; + struct fv_desc *sframe; + int i; + struct ifnet *ifp; + struct ifmultiaddr *ifma; + uint16_t *sp; + uint8_t *ma; + + ifp = sc->fv_ifp; + + i = sc->fv_cdata.fv_tx_prod; + FV_INC(sc->fv_cdata.fv_tx_prod, FV_TX_RING_CNT); + sc->fv_cdata.fv_tx_cnt++; + sframe = &sc->fv_rdata.fv_tx_ring[i]; + sp = (uint16_t *)sc->fv_cdata.fv_sf_buff; + memset(sp, 0xff, FV_SFRAME_LEN); + + sframe->fv_addr = sc->fv_rdata.fv_sf_paddr; + sframe->fv_devcs = ADCTL_Tx_SETUP | FV_DMASIZE(FV_SFRAME_LEN); + + i = 0; + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + ma = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); + sp[i] = sp[i+1] = (ma[1] << 8 | ma[0]); + i += 2; + sp[i] = sp[i+1] = (ma[3] << 8 | ma[2]); + i += 2; + sp[i] = sp[i+1] = (ma[5] << 8 | ma[4]); + i += 2; + } + if_maddr_runlock(ifp); + + bcopy(IF_LLADDR(sc->fv_ifp), eaddr, ETHER_ADDR_LEN); + sp[90] = sp[91] = eaddr[0]; + sp[92] = sp[93] = eaddr[1]; + sp[94] = sp[95] = eaddr[2]; + + sframe->fv_stat = ADSTAT_OWN; + bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag, + sc->fv_cdata.fv_tx_ring_map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->fv_cdata.fv_sf_tag, + sc->fv_cdata.fv_sf_buff_map, BUS_DMASYNC_PREWRITE); + CSR_WRITE_4(sc, CSR_TXPOLL, 0xFFFFFFFF); + DELAY(10000); +} + +static int +fv_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fv,ethernet")) + return (ENXIO); + + device_set_desc(dev, "FV Ethernet interface"); + return (BUS_PROBE_DEFAULT); +} + +static int +fv_attach(device_t dev) +{ + struct ifnet *ifp; + struct fv_softc *sc; + int error = 0, rid; + int unit; + int i; + + sc = device_get_softc(dev); + unit = device_get_unit(dev); + sc->fv_dev = dev; + sc->fv_ofw = ofw_bus_get_node(dev); + + i = OF_getprop(sc->fv_ofw, "local-mac-address", (void *)&sc->fv_eaddr, 6); + if (i != 6) { + /* hardcode macaddress */ + sc->fv_eaddr[0] = 0x00; + sc->fv_eaddr[1] = 0x0C; + sc->fv_eaddr[2] = 0x42; + sc->fv_eaddr[3] = 0x09; + sc->fv_eaddr[4] = 0x5E; + sc->fv_eaddr[5] = 0x6B; + } + + mtx_init(&sc->fv_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, + MTX_DEF); + callout_init_mtx(&sc->fv_stat_callout, &sc->fv_mtx, 0); + TASK_INIT(&sc->fv_link_task, 0, fv_link_task, sc); + + /* Map control/status registers. */ + sc->fv_rid = 0; + sc->fv_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->fv_rid, + RF_ACTIVE | RF_SHAREABLE); + + if (sc->fv_res == NULL) { + device_printf(dev, "couldn't map memory\n"); + error = ENXIO; + goto fail; + } + + sc->fv_btag = rman_get_bustag(sc->fv_res); + sc->fv_bhandle = rman_get_bushandle(sc->fv_res); + + /* Allocate interrupts */ + rid = 0; + sc->fv_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + + if (sc->fv_irq == NULL) { + device_printf(dev, "couldn't map interrupt\n"); + error = ENXIO; + goto fail; + } + + /* Allocate ifnet structure. */ + ifp = sc->fv_ifp = if_alloc(IFT_ETHER); + + if (ifp == NULL) { + device_printf(dev, "couldn't allocate ifnet structure\n"); + error = ENOSPC; + goto fail; + } + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = fv_ioctl; + ifp->if_start = fv_start; + ifp->if_init = fv_init; + + /* ifqmaxlen is sysctl value in net/if.c */ + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); + ifp->if_snd.ifq_maxlen = ifqmaxlen; + IFQ_SET_READY(&ifp->if_snd); + + ifp->if_capenable = ifp->if_capabilities; + + if (fv_dma_alloc(sc) != 0) { + error = ENXIO; + goto fail; + } + + /* TODO: calculate prescale */ +/* + CSR_WRITE_4(sc, FV_ETHMCP, (165000000 / (1250000 + 1)) & ~1); + + CSR_WRITE_4(sc, FV_MIIMCFG, FV_MIIMCFG_R); + DELAY(1000); + CSR_WRITE_4(sc, FV_MIIMCFG, 0); +*/ + CSR_WRITE_4(sc, CSR_BUSMODE, BUSMODE_SWR); + DELAY(1000); + +#ifdef FV_MDIO + sc->fv_miiproxy = mii_attach_proxy(sc->fv_dev); +#endif + +#ifdef MII + /* Do MII setup. */ + error = mii_attach(dev, &sc->fv_miibus, ifp, fv_ifmedia_upd, + fv_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); + goto fail; + } +#else + ifmedia_init(&sc->fv_ifmedia, 0, fv_ifmedia_upd, fv_ifmedia_sts); + + ifmedia_add(&sc->fv_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&sc->fv_ifmedia, IFM_ETHER | IFM_AUTO); +#endif + + /* Call MI attach routine. */ + ether_ifattach(ifp, sc->fv_eaddr); + + /* Hook interrupt last to avoid having to lock softc */ + error = bus_setup_intr(dev, sc->fv_irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, fv_intr, sc, &sc->fv_intrhand); + + if (error) { + device_printf(dev, "couldn't set up irq\n"); + ether_ifdetach(ifp); + goto fail; + } + +fail: + if (error) + fv_detach(dev); + + return (error); +} + +static int +fv_detach(device_t dev) +{ + struct fv_softc *sc = device_get_softc(dev); + struct ifnet *ifp = sc->fv_ifp; + + KASSERT(mtx_initialized(&sc->fv_mtx), ("vr mutex not initialized")); + + /* These should only be active if attach succeeded */ + if (device_is_attached(dev)) { + FV_LOCK(sc); + sc->fv_detach = 1; + fv_stop(sc); + FV_UNLOCK(sc); + taskqueue_drain(taskqueue_swi, &sc->fv_link_task); + ether_ifdetach(ifp); + } +#ifdef MII + if (sc->fv_miibus) + device_delete_child(dev, sc->fv_miibus); +#endif + bus_generic_detach(dev); + + if (sc->fv_intrhand) + bus_teardown_intr(dev, sc->fv_irq, sc->fv_intrhand); + if (sc->fv_irq) + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->fv_irq); + + if (sc->fv_res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->fv_rid, + sc->fv_res); + + if (ifp) + if_free(ifp); + + fv_dma_free(sc); + + mtx_destroy(&sc->fv_mtx); + + return (0); + +} + +static int +fv_suspend(device_t dev) +{ + + panic("%s", __func__); + return 0; +} + +static int +fv_resume(device_t dev) +{ + + panic("%s", __func__); + return 0; +} + +static int +fv_shutdown(device_t dev) +{ + struct fv_softc *sc; + + sc = device_get_softc(dev); + + FV_LOCK(sc); + fv_stop(sc); + FV_UNLOCK(sc); + + return (0); +} + +static int +fv_miibus_readbits(struct fv_softc *sc, int count) +{ + int result; + + result = 0; + while(count--) { + result <<= 1; + CSR_WRITE_4(sc, CSR_MIIMNG, MII_RD); + DELAY(10); + CSR_WRITE_4(sc, CSR_MIIMNG, MII_RD | MII_CLK); + DELAY(10); + if (CSR_READ_4(sc, CSR_MIIMNG) & MII_DIN) + result |= 1; + } + + return (result); +} + +static int +fv_miibus_writebits(struct fv_softc *sc, int data, int count) +{ + int bit; + + while(count--) { + bit = ((data) >> count) & 0x1 ? MII_DOUT : 0; + CSR_WRITE_4(sc, CSR_MIIMNG, bit | MII_WR); + DELAY(10); + CSR_WRITE_4(sc, CSR_MIIMNG, bit | MII_WR | MII_CLK); + DELAY(10); + } + + return (0); +} + +static void +fv_miibus_turnaround(struct fv_softc *sc, int cmd) +{ + if (cmd == MII_WRCMD) { + fv_miibus_writebits(sc, 0x02, 2); + } else { + fv_miibus_readbits(sc, 1); + } +} + +static int +fv_miibus_readreg(device_t dev, int phy, int reg) +{ + struct fv_softc * sc = device_get_softc(dev); + int result; + + mtx_lock(&miibus_mtx); + fv_miibus_writebits(sc, MII_PREAMBLE, 32); + fv_miibus_writebits(sc, MII_RDCMD, 4); + fv_miibus_writebits(sc, phy, 5); + fv_miibus_writebits(sc, reg, 5); + fv_miibus_turnaround(sc, MII_RDCMD); + result = fv_miibus_readbits(sc, 16); + fv_miibus_turnaround(sc, MII_RDCMD); + mtx_unlock(&miibus_mtx); + + return (result); +} + +static int +fv_miibus_writereg(device_t dev, int phy, int reg, int data) +{ + struct fv_softc * sc = device_get_softc(dev); + + mtx_lock(&miibus_mtx); + fv_miibus_writebits(sc, MII_PREAMBLE, 32); + fv_miibus_writebits(sc, MII_WRCMD, 4); + fv_miibus_writebits(sc, phy, 5); + fv_miibus_writebits(sc, reg, 5); + fv_miibus_turnaround(sc, MII_WRCMD); + fv_miibus_writebits(sc, data, 16); + mtx_unlock(&miibus_mtx); + + return (0); +} + +#if !defined(FV_MDIO) +static void +fv_miibus_statchg(device_t dev) +{ + struct fv_softc *sc; + + sc = device_get_softc(dev); + taskqueue_enqueue(taskqueue_swi, &sc->fv_link_task); +} +#endif + +static void +fv_link_task(void *arg, int pending) +{ +#ifdef MII + struct fv_softc *sc; + struct mii_data *mii; + struct ifnet *ifp; + /* int lfdx, mfdx; */ + + sc = (struct fv_softc *)arg; + + FV_LOCK(sc); + mii = device_get_softc(sc->fv_miibus); + ifp = sc->fv_ifp; + if (mii == NULL || ifp == NULL || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + FV_UNLOCK(sc); + return; + } + + if (mii->mii_media_status & IFM_ACTIVE) { + if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) + sc->fv_link_status = 1; + } else + sc->fv_link_status = 0; + + FV_UNLOCK(sc); +#endif +} + +static void +fv_reset(struct fv_softc *sc) +{ + int i; + + CSR_WRITE_4(sc, CSR_BUSMODE, BUSMODE_SWR); + + /* + * The chip doesn't take itself out of reset automatically. + * We need to do so after 2us. + */ + DELAY(1000); + CSR_WRITE_4(sc, CSR_BUSMODE, 0); + + for (i = 0; i < 1000; i++) { + /* + * Wait a bit for the reset to complete before peeking + * at the chip again. + */ + DELAY(1000); + if ((CSR_READ_4(sc, CSR_BUSMODE) & BUSMODE_SWR) == 0) + break; + } + + if (CSR_READ_4(sc, CSR_BUSMODE) & BUSMODE_SWR) + device_printf(sc->fv_dev, "reset time out\n"); + + DELAY(1000); +} + +static void +fv_init(void *xsc) +{ + struct fv_softc *sc = xsc; + + FV_LOCK(sc); + fv_init_locked(sc); + FV_UNLOCK(sc); +} + +static void +fv_init_locked(struct fv_softc *sc) +{ + struct ifnet *ifp = sc->fv_ifp; +#ifdef MII + struct mii_data *mii; +#endif + + FV_LOCK_ASSERT(sc); + +#ifdef MII + mii = device_get_softc(sc->fv_miibus); +#endif + + fv_stop(sc); + fv_reset(sc); + + /* Init circular RX list. */ + if (fv_rx_ring_init(sc) != 0) { + device_printf(sc->fv_dev, + "initialization failed: no memory for rx buffers\n"); + fv_stop(sc); + return; + } + + /* Init tx descriptors. */ + fv_tx_ring_init(sc); + + /* + * Initialize the BUSMODE register. + */ + CSR_WRITE_4(sc, CSR_BUSMODE, + /* XXX: not sure if this is a good thing or not... */ + BUSMODE_BAR | BUSMODE_PBL_32LW); + + /* + * Initialize the interrupt mask and enable interrupts. + */ + /* normal interrupts */ + sc->sc_inten = STATUS_TI | STATUS_TU | STATUS_RI | STATUS_NIS; + + /* abnormal interrupts */ + sc->sc_inten |= STATUS_TPS | STATUS_TJT | STATUS_UNF | + STATUS_RU | STATUS_RPS | STATUS_SE | STATUS_AIS; + + sc->sc_rxint_mask = STATUS_RI|STATUS_RU; + sc->sc_txint_mask = STATUS_TI|STATUS_UNF|STATUS_TJT; + + sc->sc_rxint_mask &= sc->sc_inten; + sc->sc_txint_mask &= sc->sc_inten; + + CSR_WRITE_4(sc, CSR_INTEN, sc->sc_inten); + CSR_WRITE_4(sc, CSR_STATUS, 0xffffffff); + + /* + * Give the transmit and receive rings to the chip. + */ + CSR_WRITE_4(sc, CSR_TXLIST, FV_TX_RING_ADDR(sc, 0)); + CSR_WRITE_4(sc, CSR_RXLIST, FV_RX_RING_ADDR(sc, 0)); + + /* + * Set the station address. + */ + fv_setfilt(sc); + + + /* + * Write out the opmode. + */ + CSR_WRITE_4(sc, CSR_OPMODE, OPMODE_SR | OPMODE_ST | + OPMODE_TR_128 | OPMODE_FDX | OPMODE_SPEED); + /* + * Start the receive process. + */ + CSR_WRITE_4(sc, CSR_RXPOLL, RXPOLL_RPD); + + sc->fv_link_status = 1; +#ifdef MII + mii_mediachg(mii); +#endif + + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + callout_reset(&sc->fv_stat_callout, hz, fv_tick, sc); +} + +static void +fv_start(struct ifnet *ifp) +{ + struct fv_softc *sc; + + sc = ifp->if_softc; + + FV_LOCK(sc); + fv_start_locked(ifp); + FV_UNLOCK(sc); +} + +/* + * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data + * pointers to the fragment pointers. + * Use Implicit Chain implementation. + */ +static int +fv_encap(struct fv_softc *sc, struct mbuf **m_head) +{ + struct fv_txdesc *txd; + struct fv_desc *desc; + struct mbuf *m; + bus_dma_segment_t txsegs[FV_MAXFRAGS]; + int error, i, nsegs, prod, si; + int padlen; + int txstat; + + FV_LOCK_ASSERT(sc); + + /* + * Some VIA Rhine wants packet buffers to be longword + * aligned, but very often our mbufs aren't. Rather than + * waste time trying to decide when to copy and when not + * to copy, just do it all the time. + */ + m = m_defrag(*m_head, M_NOWAIT); + if (m == NULL) { + device_printf(sc->fv_dev, "fv_encap m_defrag error\n"); + m_freem(*m_head); + *m_head = NULL; + return (ENOBUFS); + } + *m_head = m; + + /* + * The Rhine chip doesn't auto-pad, so we have to make + * sure to pad short frames out to the minimum frame length + * ourselves. + */ + if ((*m_head)->m_pkthdr.len < FV_MIN_FRAMELEN) { + m = *m_head; + padlen = FV_MIN_FRAMELEN - m->m_pkthdr.len; + if (M_WRITABLE(m) == 0) { + /* Get a writable copy. */ + m = m_dup(*m_head, M_NOWAIT); + m_freem(*m_head); + if (m == NULL) { + device_printf(sc->fv_dev, "fv_encap m_dup error\n"); + *m_head = NULL; + return (ENOBUFS); + } + *m_head = m; + } + if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) { + m = m_defrag(m, M_NOWAIT); + if (m == NULL) { + device_printf(sc->fv_dev, "fv_encap m_defrag error\n"); + m_freem(*m_head); + *m_head = NULL; + return (ENOBUFS); + } + } + /* + * Manually pad short frames, and zero the pad space + * to avoid leaking data. + */ + bzero(mtod(m, char *) + m->m_pkthdr.len, padlen); + m->m_pkthdr.len += padlen; + m->m_len = m->m_pkthdr.len; + *m_head = m; + } + + prod = sc->fv_cdata.fv_tx_prod; + txd = &sc->fv_cdata.fv_txdesc[prod]; + error = bus_dmamap_load_mbuf_sg(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap, + *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); + if (error == EFBIG) { + device_printf(sc->fv_dev, "fv_encap EFBIG error\n"); + m = m_defrag(*m_head, M_NOWAIT); + if (m == NULL) { + m_freem(*m_head); + *m_head = NULL; + return (ENOBUFS); + } + *m_head = m; + error = bus_dmamap_load_mbuf_sg(sc->fv_cdata.fv_tx_tag, + txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + m_freem(*m_head); + *m_head = NULL; + return (error); + } + + } else if (error != 0) + return (error); + if (nsegs == 0) { + m_freem(*m_head); + *m_head = NULL; + return (EIO); + } + + /* Check number of available descriptors. */ + if (sc->fv_cdata.fv_tx_cnt + nsegs >= (FV_TX_RING_CNT - 1)) { + bus_dmamap_unload(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap); + return (ENOBUFS); + } + + txd->tx_m = *m_head; + bus_dmamap_sync(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap, + BUS_DMASYNC_PREWRITE); + + si = prod; + + /* + * Make a list of descriptors for this packet. + */ + desc = NULL; + for (i = 0; i < nsegs; i++) { + desc = &sc->fv_rdata.fv_tx_ring[prod]; + desc->fv_stat = ADSTAT_OWN; + desc->fv_devcs = txsegs[i].ds_len; + /* end of descriptor */ + if (prod == FV_TX_RING_CNT - 1) + desc->fv_devcs |= ADCTL_ER; + desc->fv_addr = txsegs[i].ds_addr; + + ++sc->fv_cdata.fv_tx_cnt; + FV_INC(prod, FV_TX_RING_CNT); + } + + /* + * Set mark last fragment with Last/Intr flag + */ + if (desc) { + desc->fv_devcs |= ADCTL_Tx_IC; + desc->fv_devcs |= ADCTL_Tx_LS; + } + + /* Update producer index. */ + sc->fv_cdata.fv_tx_prod = prod; + + /* Sync descriptors. */ + bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag, + sc->fv_cdata.fv_tx_ring_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7; + if (txstat == 0 || txstat == 6) { + /* Transmit Process Stat is stop or suspended */ + desc = &sc->fv_rdata.fv_tx_ring[si]; + desc->fv_devcs |= ADCTL_Tx_FS; + } + else { + /* Get previous descriptor */ + si = (si + FV_TX_RING_CNT - 1) % FV_TX_RING_CNT; + desc = &sc->fv_rdata.fv_tx_ring[si]; + /* join remain data and flugs */ + desc->fv_devcs &= ~ADCTL_Tx_IC; + desc->fv_devcs &= ~ADCTL_Tx_LS; + } + + + return (0); +} + +static void +fv_start_locked(struct ifnet *ifp) +{ + struct fv_softc *sc; + struct mbuf *m_head; + int enq; + int txstat; + + sc = ifp->if_softc; + + FV_LOCK_ASSERT(sc); + + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING || sc->fv_link_status == 0 ) + return; + + for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && + sc->fv_cdata.fv_tx_cnt < FV_TX_RING_CNT - 2; ) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); + if (m_head == NULL) + break; + /* + * Pack the data into the transmit ring. If we + * don't have room, set the OACTIVE flag and wait + * for the NIC to drain the ring. + */ + if (fv_encap(sc, &m_head)) { + if (m_head == NULL) + break; + IFQ_DRV_PREPEND(&ifp->if_snd, m_head); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + + enq++; + /* + * If there's a BPF listener, bounce a copy of this frame + * to him. + */ + ETHER_BPF_MTAP(ifp, m_head); + } + + if (enq > 0) { + txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7; + if (txstat == 0 || txstat == 6) + CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD); + } +} + +static void +fv_stop(struct fv_softc *sc) +{ + struct ifnet *ifp; + + FV_LOCK_ASSERT(sc); + + ifp = sc->fv_ifp; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + callout_stop(&sc->fv_stat_callout); + + /* Disable interrupts. */ + CSR_WRITE_4(sc, CSR_INTEN, 0); + + /* Stop the transmit and receive processes. */ + CSR_WRITE_4(sc, CSR_OPMODE, 0); + CSR_WRITE_4(sc, CSR_RXLIST, 0); + CSR_WRITE_4(sc, CSR_TXLIST, 0); + +} + + +static int +fv_ioctl(struct ifnet *ifp, u_long command, caddr_t data) +{ + struct fv_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; +#ifdef MII + struct mii_data *mii; +#endif + int error; + int csr; + + switch (command) { + case SIOCSIFFLAGS: + FV_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if ((ifp->if_flags ^ sc->fv_if_flags) & + IFF_PROMISC) { + csr = CSR_READ_4(sc, CSR_OPMODE); + CSR_WRITE_4(sc, CSR_OPMODE, csr | + OPMODE_PM | OPMODE_PR); + } + if ((ifp->if_flags ^ sc->fv_if_flags) & + IFF_ALLMULTI) { + csr = CSR_READ_4(sc, CSR_OPMODE); + CSR_WRITE_4(sc, CSR_OPMODE, csr | + OPMODE_PM); + } + } else { + if (sc->fv_detach == 0) + fv_init_locked(sc); + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + fv_stop(sc); + } + sc->fv_if_flags = ifp->if_flags; + FV_UNLOCK(sc); + error = 0; + break; + case SIOCADDMULTI: + case SIOCDELMULTI: +#if 0 + FV_LOCK(sc); + fv_set_filter(sc); + FV_UNLOCK(sc); +#endif + error = 0; + break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: +#ifdef MII + mii = device_get_softc(sc->fv_miibus); + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); +#else + error = ifmedia_ioctl(ifp, ifr, &sc->fv_ifmedia, command); +#endif + break; + case SIOCSIFCAP: + error = 0; +#if 0 + mask = ifr->ifr_reqcap ^ ifp->if_capenable; + if ((mask & IFCAP_HWCSUM) != 0) { + ifp->if_capenable ^= IFCAP_HWCSUM; + if ((IFCAP_HWCSUM & ifp->if_capenable) && + (IFCAP_HWCSUM & ifp->if_capabilities)) + ifp->if_hwassist = FV_CSUM_FEATURES; + else + ifp->if_hwassist = 0; + } + if ((mask & IFCAP_VLAN_HWTAGGING) != 0) { + ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; + if (IFCAP_VLAN_HWTAGGING & ifp->if_capenable && + IFCAP_VLAN_HWTAGGING & ifp->if_capabilities && + ifp->if_drv_flags & IFF_DRV_RUNNING) { + FV_LOCK(sc); + fv_vlan_setup(sc); + FV_UNLOCK(sc); + } + } + VLAN_CAPABILITIES(ifp); +#endif + break; + default: + error = ether_ioctl(ifp, command, data); + break; + } + + return (error); +} + +/* + * Set media options. + */ +static int +fv_ifmedia_upd(struct ifnet *ifp) +{ +#ifdef MII + struct fv_softc *sc; + struct mii_data *mii; + struct mii_softc *miisc; + int error; + + sc = ifp->if_softc; + FV_LOCK(sc); + mii = device_get_softc(sc->fv_miibus); + LIST_FOREACH(miisc, &mii->mii_phys, mii_list) + PHY_RESET(miisc); + error = mii_mediachg(mii); + FV_UNLOCK(sc); + + return (error); +#else + return (0); +#endif +} + +/* + * Report current media status. + */ +static void +fv_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) +{ +#ifdef MII + struct fv_softc *sc = ifp->if_softc; + struct mii_data *mii; + + mii = device_get_softc(sc->fv_miibus); + FV_LOCK(sc); + mii_pollstat(mii); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; + FV_UNLOCK(sc); +#else + ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; +#endif +} + +struct fv_dmamap_arg { + bus_addr_t fv_busaddr; +}; + +static void +fv_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct fv_dmamap_arg *ctx; + + if (error != 0) + return; + ctx = arg; + ctx->fv_busaddr = segs[0].ds_addr; +} + +static int +fv_dma_alloc(struct fv_softc *sc) +{ + struct fv_dmamap_arg ctx; + struct fv_txdesc *txd; + struct fv_rxdesc *rxd; + int error, i; + + /* Create parent DMA tag. */ + error = bus_dma_tag_create( + bus_get_dma_tag(sc->fv_dev), /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ + 0, /* nsegments */ + BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->fv_cdata.fv_parent_tag); + if (error != 0) { + device_printf(sc->fv_dev, "failed to create parent DMA tag\n"); + goto fail; + } + /* Create tag for Tx ring. */ + error = bus_dma_tag_create( + sc->fv_cdata.fv_parent_tag, /* parent */ + FV_RING_ALIGN, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + FV_TX_RING_SIZE, /* maxsize */ + 1, /* nsegments */ + FV_TX_RING_SIZE, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->fv_cdata.fv_tx_ring_tag); + if (error != 0) { + device_printf(sc->fv_dev, "failed to create Tx ring DMA tag\n"); + goto fail; + } + + /* Create tag for Rx ring. */ + error = bus_dma_tag_create( + sc->fv_cdata.fv_parent_tag, /* parent */ + FV_RING_ALIGN, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + FV_RX_RING_SIZE, /* maxsize */ + 1, /* nsegments */ + FV_RX_RING_SIZE, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->fv_cdata.fv_rx_ring_tag); + if (error != 0) { + device_printf(sc->fv_dev, "failed to create Rx ring DMA tag\n"); + goto fail; + } + + /* Create tag for Tx buffers. */ + error = bus_dma_tag_create( + sc->fv_cdata.fv_parent_tag, /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MCLBYTES * FV_MAXFRAGS, /* maxsize */ + FV_MAXFRAGS, /* nsegments */ + MCLBYTES, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->fv_cdata.fv_tx_tag); + if (error != 0) { + device_printf(sc->fv_dev, "failed to create Tx DMA tag\n"); + goto fail; + } + + /* Create tag for Rx buffers. */ + error = bus_dma_tag_create( + sc->fv_cdata.fv_parent_tag, /* parent */ + FV_RX_ALIGN, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + MCLBYTES, /* maxsize */ + 1, /* nsegments */ + MCLBYTES, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->fv_cdata.fv_rx_tag); + if (error != 0) { + device_printf(sc->fv_dev, "failed to create Rx DMA tag\n"); + goto fail; + } + + /* Create tag for setup frame buffers. */ + error = bus_dma_tag_create( + sc->fv_cdata.fv_parent_tag, /* parent */ + sizeof(uint32_t), 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + FV_SFRAME_LEN + FV_MIN_FRAMELEN, /* maxsize */ + 1, /* nsegments */ + FV_SFRAME_LEN + FV_MIN_FRAMELEN, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->fv_cdata.fv_sf_tag); + if (error != 0) { + device_printf(sc->fv_dev, "failed to create setup frame DMA tag\n"); + goto fail; + } + + /* Allocate DMA'able memory and load the DMA map for Tx ring. */ + error = bus_dmamem_alloc(sc->fv_cdata.fv_tx_ring_tag, + (void **)&sc->fv_rdata.fv_tx_ring, BUS_DMA_WAITOK | + BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->fv_cdata.fv_tx_ring_map); + if (error != 0) { + device_printf(sc->fv_dev, + "failed to allocate DMA'able memory for Tx ring\n"); + goto fail; + } + + ctx.fv_busaddr = 0; + error = bus_dmamap_load(sc->fv_cdata.fv_tx_ring_tag, + sc->fv_cdata.fv_tx_ring_map, sc->fv_rdata.fv_tx_ring, + FV_TX_RING_SIZE, fv_dmamap_cb, &ctx, 0); + if (error != 0 || ctx.fv_busaddr == 0) { + device_printf(sc->fv_dev, + "failed to load DMA'able memory for Tx ring\n"); + goto fail; + } + sc->fv_rdata.fv_tx_ring_paddr = ctx.fv_busaddr; + + /* Allocate DMA'able memory and load the DMA map for Rx ring. */ + error = bus_dmamem_alloc(sc->fv_cdata.fv_rx_ring_tag, + (void **)&sc->fv_rdata.fv_rx_ring, BUS_DMA_WAITOK | + BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->fv_cdata.fv_rx_ring_map); + if (error != 0) { + device_printf(sc->fv_dev, + "failed to allocate DMA'able memory for Rx ring\n"); + goto fail; + } + + ctx.fv_busaddr = 0; + error = bus_dmamap_load(sc->fv_cdata.fv_rx_ring_tag, + sc->fv_cdata.fv_rx_ring_map, sc->fv_rdata.fv_rx_ring, + FV_RX_RING_SIZE, fv_dmamap_cb, &ctx, 0); + if (error != 0 || ctx.fv_busaddr == 0) { + device_printf(sc->fv_dev, + "failed to load DMA'able memory for Rx ring\n"); + goto fail; + } + sc->fv_rdata.fv_rx_ring_paddr = ctx.fv_busaddr; + + /* Allocate DMA'able memory and load the DMA map for setup frame. */ + error = bus_dmamem_alloc(sc->fv_cdata.fv_sf_tag, + (void **)&sc->fv_cdata.fv_sf_buff, BUS_DMA_WAITOK | + BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->fv_cdata.fv_sf_buff_map); + if (error != 0) { + device_printf(sc->fv_dev, + "failed to allocate DMA'able memory for setup frame\n"); + goto fail; + } + + ctx.fv_busaddr = 0; + error = bus_dmamap_load(sc->fv_cdata.fv_sf_tag, + sc->fv_cdata.fv_sf_buff_map, sc->fv_cdata.fv_sf_buff, + FV_SFRAME_LEN, fv_dmamap_cb, &ctx, 0); + if (error != 0 || ctx.fv_busaddr == 0) { + device_printf(sc->fv_dev, + "failed to load DMA'able memory for setup frame\n"); + goto fail; + } + sc->fv_rdata.fv_sf_paddr = ctx.fv_busaddr; + + /* Create DMA maps for Tx buffers. */ + for (i = 0; i < FV_TX_RING_CNT; i++) { + txd = &sc->fv_cdata.fv_txdesc[i]; + txd->tx_m = NULL; + txd->tx_dmamap = NULL; + error = bus_dmamap_create(sc->fv_cdata.fv_tx_tag, 0, + &txd->tx_dmamap); + if (error != 0) { + device_printf(sc->fv_dev, + "failed to create Tx dmamap\n"); + goto fail; + } + } + /* Create DMA maps for Rx buffers. */ + if ((error = bus_dmamap_create(sc->fv_cdata.fv_rx_tag, 0, + &sc->fv_cdata.fv_rx_sparemap)) != 0) { + device_printf(sc->fv_dev, + "failed to create spare Rx dmamap\n"); + goto fail; + } + for (i = 0; i < FV_RX_RING_CNT; i++) { + rxd = &sc->fv_cdata.fv_rxdesc[i]; + rxd->rx_m = NULL; + rxd->rx_dmamap = NULL; + error = bus_dmamap_create(sc->fv_cdata.fv_rx_tag, 0, + &rxd->rx_dmamap); + if (error != 0) { + device_printf(sc->fv_dev, + "failed to create Rx dmamap\n"); + goto fail; + } + } + +fail: + return (error); +} + +static void +fv_dma_free(struct fv_softc *sc) +{ + struct fv_txdesc *txd; + struct fv_rxdesc *rxd; + int i; + + /* Tx ring. */ + if (sc->fv_cdata.fv_tx_ring_tag) { + if (sc->fv_rdata.fv_tx_ring_paddr) + bus_dmamap_unload(sc->fv_cdata.fv_tx_ring_tag, + sc->fv_cdata.fv_tx_ring_map); + if (sc->fv_rdata.fv_tx_ring) + bus_dmamem_free(sc->fv_cdata.fv_tx_ring_tag, + sc->fv_rdata.fv_tx_ring, + sc->fv_cdata.fv_tx_ring_map); + sc->fv_rdata.fv_tx_ring = NULL; + sc->fv_rdata.fv_tx_ring_paddr = 0; + bus_dma_tag_destroy(sc->fv_cdata.fv_tx_ring_tag); + sc->fv_cdata.fv_tx_ring_tag = NULL; + } + /* Rx ring. */ + if (sc->fv_cdata.fv_rx_ring_tag) { + if (sc->fv_rdata.fv_rx_ring_paddr) + bus_dmamap_unload(sc->fv_cdata.fv_rx_ring_tag, + sc->fv_cdata.fv_rx_ring_map); + if (sc->fv_rdata.fv_rx_ring) + bus_dmamem_free(sc->fv_cdata.fv_rx_ring_tag, + sc->fv_rdata.fv_rx_ring, + sc->fv_cdata.fv_rx_ring_map); + sc->fv_rdata.fv_rx_ring = NULL; + sc->fv_rdata.fv_rx_ring_paddr = 0; + bus_dma_tag_destroy(sc->fv_cdata.fv_rx_ring_tag); + sc->fv_cdata.fv_rx_ring_tag = NULL; + } + /* Tx buffers. */ + if (sc->fv_cdata.fv_tx_tag) { + for (i = 0; i < FV_TX_RING_CNT; i++) { + txd = &sc->fv_cdata.fv_txdesc[i]; + if (txd->tx_dmamap) { + bus_dmamap_destroy(sc->fv_cdata.fv_tx_tag, + txd->tx_dmamap); + txd->tx_dmamap = NULL; + } + } + bus_dma_tag_destroy(sc->fv_cdata.fv_tx_tag); + sc->fv_cdata.fv_tx_tag = NULL; + } + /* Rx buffers. */ + if (sc->fv_cdata.fv_rx_tag) { + for (i = 0; i < FV_RX_RING_CNT; i++) { + rxd = &sc->fv_cdata.fv_rxdesc[i]; + if (rxd->rx_dmamap) { + bus_dmamap_destroy(sc->fv_cdata.fv_rx_tag, + rxd->rx_dmamap); + rxd->rx_dmamap = NULL; + } + } + if (sc->fv_cdata.fv_rx_sparemap) { + bus_dmamap_destroy(sc->fv_cdata.fv_rx_tag, + sc->fv_cdata.fv_rx_sparemap); + sc->fv_cdata.fv_rx_sparemap = 0; + } + bus_dma_tag_destroy(sc->fv_cdata.fv_rx_tag); + sc->fv_cdata.fv_rx_tag = NULL; + } + + if (sc->fv_cdata.fv_parent_tag) { + bus_dma_tag_destroy(sc->fv_cdata.fv_parent_tag); + sc->fv_cdata.fv_parent_tag = NULL; + } +} + +/* + * Initialize the transmit descriptors. + */ +static int +fv_tx_ring_init(struct fv_softc *sc) +{ + struct fv_ring_data *rd; + struct fv_txdesc *txd; + bus_addr_t addr; + int i; + + sc->fv_cdata.fv_tx_prod = 0; + sc->fv_cdata.fv_tx_cons = 0; + sc->fv_cdata.fv_tx_cnt = 0; + sc->fv_cdata.fv_tx_pkts = 0; + + rd = &sc->fv_rdata; + bzero(rd->fv_tx_ring, FV_TX_RING_SIZE); + for (i = 0; i < FV_TX_RING_CNT; i++) { + if (i == FV_TX_RING_CNT - 1) + addr = FV_TX_RING_ADDR(sc, 0); + else + addr = FV_TX_RING_ADDR(sc, i + 1); + rd->fv_tx_ring[i].fv_stat = 0; + rd->fv_tx_ring[i].fv_devcs = 0; + rd->fv_tx_ring[i].fv_addr = 0; + rd->fv_tx_ring[i].fv_link = addr; + txd = &sc->fv_cdata.fv_txdesc[i]; + txd->tx_m = NULL; + } + + bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag, + sc->fv_cdata.fv_tx_ring_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + return (0); +} + +/* + * Initialize the RX descriptors and allocate mbufs for them. Note that + * we arrange the descriptors in a closed ring, so that the last descriptor + * points back to the first. + */ +static int +fv_rx_ring_init(struct fv_softc *sc) +{ + struct fv_ring_data *rd; + struct fv_rxdesc *rxd; + int i; + + sc->fv_cdata.fv_rx_cons = 0; + + rd = &sc->fv_rdata; + bzero(rd->fv_rx_ring, FV_RX_RING_SIZE); + for (i = 0; i < FV_RX_RING_CNT; i++) { + rxd = &sc->fv_cdata.fv_rxdesc[i]; + rxd->rx_m = NULL; + rxd->desc = &rd->fv_rx_ring[i]; + rd->fv_rx_ring[i].fv_stat = ADSTAT_OWN; + rd->fv_rx_ring[i].fv_devcs = 0; + if (i == FV_RX_RING_CNT - 1) + rd->fv_rx_ring[i].fv_devcs |= ADCTL_ER; + rd->fv_rx_ring[i].fv_addr = 0; + if (fv_newbuf(sc, i) != 0) + return (ENOBUFS); + } + + bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag, + sc->fv_cdata.fv_rx_ring_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + return (0); +} + +/* + * Initialize an RX descriptor and attach an MBUF cluster. + */ +static int +fv_newbuf(struct fv_softc *sc, int idx) +{ + struct fv_desc *desc; + struct fv_rxdesc *rxd; + struct mbuf *m; + bus_dma_segment_t segs[1]; + bus_dmamap_t map; + int nsegs; + + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) + return (ENOBUFS); + m->m_len = m->m_pkthdr.len = MCLBYTES; + + /* tcp header boundary alignment margin */ + m_adj(m, 4); + + if (bus_dmamap_load_mbuf_sg(sc->fv_cdata.fv_rx_tag, + sc->fv_cdata.fv_rx_sparemap, m, segs, &nsegs, 0) != 0) { + m_freem(m); + return (ENOBUFS); + } + KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); + + rxd = &sc->fv_cdata.fv_rxdesc[idx]; + if (rxd->rx_m != NULL) { +/* This code make bug. Make scranble on buffer data. + bus_dmamap_sync(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap, + BUS_DMASYNC_POSTREAD); +*/ + bus_dmamap_unload(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap); + } + map = rxd->rx_dmamap; + rxd->rx_dmamap = sc->fv_cdata.fv_rx_sparemap; + sc->fv_cdata.fv_rx_sparemap = map; + bus_dmamap_sync(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap, + BUS_DMASYNC_PREREAD); + rxd->rx_m = m; + desc = rxd->desc; + desc->fv_addr = segs[0].ds_addr; + desc->fv_devcs |= FV_DMASIZE(segs[0].ds_len); + rxd->saved_ca = desc->fv_addr ; + rxd->saved_ctl = desc->fv_stat ; + + return (0); +} + +static __inline void +fv_fixup_rx(struct mbuf *m) +{ + int i; + uint16_t *src, *dst; + + src = mtod(m, uint16_t *); + dst = src - 1; + + for (i = 0; i < m->m_len / sizeof(uint16_t); i++) { + *dst++ = *src++; + } + + if (m->m_len % sizeof(uint16_t)) + *(uint8_t *)dst = *(uint8_t *)src; + + m->m_data -= ETHER_ALIGN; +} + + +static void +fv_tx(struct fv_softc *sc) +{ + struct fv_txdesc *txd; + struct fv_desc *cur_tx; + struct ifnet *ifp; + uint32_t ctl, devcs; + int cons, prod, prev_cons; + + FV_LOCK_ASSERT(sc); + + cons = sc->fv_cdata.fv_tx_cons; + prod = sc->fv_cdata.fv_tx_prod; + if (cons == prod) + return; + + bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag, + sc->fv_cdata.fv_tx_ring_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + ifp = sc->fv_ifp; + /* + * Go through our tx list and free mbufs for those + * frames that have been transmitted. + */ + prev_cons = cons; + for (; cons != prod; FV_INC(cons, FV_TX_RING_CNT)) { + cur_tx = &sc->fv_rdata.fv_tx_ring[cons]; + ctl = cur_tx->fv_stat; + devcs = cur_tx->fv_devcs; + /* Check if descriptor has "finished" flag */ + if (FV_DMASIZE(devcs) == 0) + break; + + sc->fv_cdata.fv_tx_cnt--; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + txd = &sc->fv_cdata.fv_txdesc[cons]; + + if ((ctl & ADSTAT_Tx_ES) == 0) + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + else if (ctl & ADSTAT_Tx_UF) { /* only underflow not check collision */ + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + } + + bus_dmamap_sync(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->fv_cdata.fv_tx_tag, txd->tx_dmamap); + + /* Free only if it's first descriptor in list */ + if (txd->tx_m) + m_freem(txd->tx_m); + txd->tx_m = NULL; + + /* reset descriptor */ + cur_tx->fv_stat = 0; + cur_tx->fv_devcs = 0; + cur_tx->fv_addr = 0; + } + + sc->fv_cdata.fv_tx_cons = cons; + + bus_dmamap_sync(sc->fv_cdata.fv_tx_ring_tag, + sc->fv_cdata.fv_tx_ring_map, BUS_DMASYNC_PREWRITE); +} + + +static void +fv_rx(struct fv_softc *sc) +{ + struct fv_rxdesc *rxd; + struct ifnet *ifp = sc->fv_ifp; + int cons, prog, packet_len, error; + struct fv_desc *cur_rx; + struct mbuf *m; + + FV_LOCK_ASSERT(sc); + + cons = sc->fv_cdata.fv_rx_cons; + + bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag, + sc->fv_cdata.fv_rx_ring_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + for (prog = 0; prog < FV_RX_RING_CNT; FV_INC(cons, FV_RX_RING_CNT)) { + cur_rx = &sc->fv_rdata.fv_rx_ring[cons]; + rxd = &sc->fv_cdata.fv_rxdesc[cons]; + m = rxd->rx_m; + + if ((cur_rx->fv_stat & ADSTAT_OWN) == ADSTAT_OWN) + break; + + prog++; + + if (cur_rx->fv_stat & (ADSTAT_ES | ADSTAT_Rx_TL)) { + device_printf(sc->fv_dev, + "Receive Descriptor error %x\n", cur_rx->fv_stat); + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + packet_len = 0; + } else { + packet_len = ADSTAT_Rx_LENGTH(cur_rx->fv_stat); + } + + /* Assume it's error */ + error = 1; + + if (packet_len < 64) + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + else if ((cur_rx->fv_stat & ADSTAT_Rx_DE) == 0) { + error = 0; + bus_dmamap_sync(sc->fv_cdata.fv_rx_tag, rxd->rx_dmamap, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + m = rxd->rx_m; + /* Skip 4 bytes of CRC */ + m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN; + + fv_fixup_rx(m); + m->m_pkthdr.rcvif = ifp; + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); + + FV_UNLOCK(sc); + (*ifp->if_input)(ifp, m); + FV_LOCK(sc); + } + + if (error) { + /* Restore CONTROL and CA values, reset DEVCS */ + cur_rx->fv_stat = rxd->saved_ctl; + cur_rx->fv_addr = rxd->saved_ca; + cur_rx->fv_devcs = 0; + } + else { + /* Reinit descriptor */ + cur_rx->fv_stat = ADSTAT_OWN; + cur_rx->fv_devcs = 0; + if (cons == FV_RX_RING_CNT - 1) + cur_rx->fv_devcs |= ADCTL_ER; + cur_rx->fv_addr = 0; + if (fv_newbuf(sc, cons) != 0) { + device_printf(sc->fv_dev, + "Failed to allocate buffer\n"); + break; + } + } + + bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag, + sc->fv_cdata.fv_rx_ring_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + } + + if (prog > 0) { + sc->fv_cdata.fv_rx_cons = cons; + + bus_dmamap_sync(sc->fv_cdata.fv_rx_ring_tag, + sc->fv_cdata.fv_rx_ring_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + } +} + +static void +fv_intr(void *arg) +{ + struct fv_softc *sc = arg; + uint32_t status; + struct ifnet *ifp = sc->fv_ifp; + + FV_LOCK(sc); + + status = CSR_READ_4(sc, CSR_STATUS); + /* mask out interrupts */ + while((status & sc->sc_inten) != 0) { + if (status) { + CSR_WRITE_4(sc, CSR_STATUS, status); + } + if (status & STATUS_UNF) { + device_printf(sc->fv_dev, "Transmit Underflow\n"); + } + if (status & sc->sc_rxint_mask) { + fv_rx(sc); + } + if (status & sc->sc_txint_mask) { + fv_tx(sc); + } + if (status & STATUS_AIS) { + device_printf(sc->fv_dev, "Abnormal Interrupt %x\n", + status); + } + CSR_WRITE_4(sc, CSR_FULLDUP, FULLDUP_CS | + (1 << FULLDUP_TT_SHIFT) | (3 << FULLDUP_NTP_SHIFT) | + (2 << FULLDUP_RT_SHIFT) | (2 << FULLDUP_NRP_SHIFT)); + + + status = CSR_READ_4(sc, CSR_STATUS); + } + + /* Try to get more packets going. */ + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + fv_start_locked(ifp); + + FV_UNLOCK(sc); +} + +static void +fv_tick(void *xsc) +{ + struct fv_softc *sc = xsc; +#ifdef MII + struct mii_data *mii; + + FV_LOCK_ASSERT(sc); + + mii = device_get_softc(sc->fv_miibus); + mii_tick(mii); +#endif + callout_reset(&sc->fv_stat_callout, hz, fv_tick, sc); +} + +static void +fv_hinted_child(device_t bus, const char *dname, int dunit) +{ + BUS_ADD_CHILD(bus, 0, dname, dunit); + device_printf(bus, "hinted child %s%d\n", dname, dunit); +} + +#ifdef FV_MDIO +static int +fvmdio_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fv,mdio")) + return (ENXIO); + + device_set_desc(dev, "FV built-in ethernet interface, MDIO controller"); + return(0); +} + +static int +fvmdio_attach(device_t dev) +{ + struct fv_softc *sc; + int error; + + sc = device_get_softc(dev); + sc->fv_dev = dev; + sc->fv_rid = 0; + sc->fv_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->fv_rid, RF_ACTIVE | RF_SHAREABLE); + if (sc->fv_res == NULL) { + device_printf(dev, "couldn't map memory\n"); + error = ENXIO; + goto fail; + } + + sc->fv_btag = rman_get_bustag(sc->fv_res); + sc->fv_bhandle = rman_get_bushandle(sc->fv_res); + + bus_generic_probe(dev); + bus_enumerate_hinted_children(dev); + error = bus_generic_attach(dev); +fail: + return(error); +} + +static int +fvmdio_detach(device_t dev) +{ + return(0); +} +#endif + +#ifdef FV_DEBUG +void +dump_txdesc(struct fv_softc *sc, int pos) +{ + struct fv_desc *desc; + + desc = &sc->fv_rdata.fv_tx_ring[pos]; + device_printf(sc->fv_dev, "CSR_TXLIST %08x\n", CSR_READ_4(sc, CSR_TXLIST)); + device_printf(sc->fv_dev, "%d TDES0:%08x TDES1:%08x TDES2:%08x TDES3:%08x\n", + pos, desc->fv_stat, desc->fv_devcs, desc->fv_addr, desc->fv_link); +} + +void +dump_status_reg(struct fv_softc *sc) +{ + uint32_t status; + + /* mask out interrupts */ + + status = CSR_READ_4(sc, CSR_STATUS); + device_printf(sc->fv_dev, "CSR5 Status Register EB:%d TS:%d RS:%d NIS:%d AIS:%d ER:%d SE:%d LNF:%d TM:%d RWT:%d RPS:%d RU:%d RI:%d UNF:%d LNP/ANC:%d TJT:%d TU:%d TPS:%d TI:%d\n", + (status >> 23 ) & 7, + (status >> 20 ) & 7, + (status >> 17 ) & 7, + (status >> 16 ) & 1, + (status >> 15 ) & 1, + (status >> 14 ) & 1, + (status >> 13 ) & 1, + (status >> 12 ) & 1, + (status >> 11 ) & 1, + (status >> 9 ) & 1, + (status >> 8 ) & 1, + (status >> 7 ) & 1, + (status >> 6 ) & 1, + (status >> 5 ) & 1, + (status >> 4 ) & 1, + (status >> 3 ) & 1, + (status >> 2 ) & 1, + (status >> 1 ) & 1, + (status >> 0 ) & 1); + +} +#endif Property changes on: head/sys/arm/ralink/if_fv.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ralink/if_fvreg.h =================================================================== --- head/sys/arm/ralink/if_fvreg.h (nonexistent) +++ head/sys/arm/ralink/if_fvreg.h (revision 317872) @@ -0,0 +1,452 @@ +/*- + * Copyright (C) 2007 + * Oleksandr Tymoshenko . 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 SOFTWFV IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE FV DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES 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 MIND, 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 SOFTWFV, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#ifndef __IF_FVREG_H__ +#define __IF_FVREG_H__ + +struct fv_desc { + uint32_t fv_stat; + uint32_t fv_devcs; + uint32_t fv_addr; + uint32_t fv_link; +}; + +#define FV_DMASIZE(len) ((len) & ((1 << 11)-1)) +#define FV_PKTSIZE(len) ((len & 0xffff0000) >> 16) + +#define FV_RX_RING_CNT 128 +#define FV_TX_RING_CNT 128 +#define FV_TX_RING_SIZE sizeof(struct fv_desc) * FV_TX_RING_CNT +#define FV_RX_RING_SIZE sizeof(struct fv_desc) * FV_RX_RING_CNT +#define FV_RING_ALIGN sizeof(struct fv_desc) +#define FV_RX_ALIGN sizeof(uint32_t) +#define FV_MAXFRAGS 8 +#define FV_TX_INTR_THRESH 8 + +#define FV_TX_RING_ADDR(sc, i) \ + ((sc)->fv_rdata.fv_tx_ring_paddr + sizeof(struct fv_desc) * (i)) +#define FV_RX_RING_ADDR(sc, i) \ + ((sc)->fv_rdata.fv_rx_ring_paddr + sizeof(struct fv_desc) * (i)) +#define FV_INC(x,y) (x) = (((x) + 1) % y) + +struct fv_txdesc { + struct mbuf *tx_m; + bus_dmamap_t tx_dmamap; +}; + +struct fv_rxdesc { + struct mbuf *rx_m; + bus_dmamap_t rx_dmamap; + struct fv_desc *desc; + /* Use this values on error instead of allocating new mbuf */ + uint32_t saved_ctl, saved_ca; +}; + +struct fv_chain_data { + bus_dma_tag_t fv_parent_tag; + bus_dma_tag_t fv_tx_tag; + struct fv_txdesc fv_txdesc[FV_TX_RING_CNT]; + bus_dma_tag_t fv_rx_tag; + struct fv_rxdesc fv_rxdesc[FV_RX_RING_CNT]; + bus_dma_tag_t fv_tx_ring_tag; + bus_dma_tag_t fv_rx_ring_tag; + bus_dmamap_t fv_tx_ring_map; + bus_dmamap_t fv_rx_ring_map; + bus_dmamap_t fv_rx_sparemap; + int fv_tx_pkts; + int fv_tx_prod; + int fv_tx_cons; + int fv_tx_cnt; + int fv_rx_cons; + + bus_dma_tag_t fv_sf_tag; + bus_dmamap_t fv_sf_buff_map; + uint32_t *fv_sf_buff; +}; + +struct fv_ring_data { + struct fv_desc *fv_rx_ring; + struct fv_desc *fv_tx_ring; + bus_addr_t fv_rx_ring_paddr; + bus_addr_t fv_tx_ring_paddr; + bus_addr_t fv_sf_paddr; +}; + +struct fv_softc { + struct ifnet *fv_ifp; /* interface info */ + bus_space_handle_t fv_bhandle; /* bus space handle */ + bus_space_tag_t fv_btag; /* bus space tag */ + device_t fv_dev; + uint8_t fv_eaddr[ETHER_ADDR_LEN]; + struct resource *fv_res; + int fv_rid; + struct resource *fv_irq; + void *fv_intrhand; + u_int32_t sc_inten; /* copy of CSR_INTEN */ + u_int32_t sc_rxint_mask; /* mask of Rx interrupts we want */ + u_int32_t sc_txint_mask; /* mask of Tx interrupts we want */ +#ifdef MII + device_t fv_miibus; +#else + struct ifmedia fv_ifmedia; +#endif +#ifdef FV_MDIO + device_t fv_miiproxy; +#endif + int fv_if_flags; + bus_dma_tag_t fv_parent_tag; + bus_dma_tag_t fv_tag; + struct mtx fv_mtx; + phandle_t fv_ofw; + struct callout fv_stat_callout; + struct task fv_link_task; + struct fv_chain_data fv_cdata; + struct fv_ring_data fv_rdata; + int fv_link_status; + int fv_detach; +}; + +#define FV_LOCK(_sc) mtx_lock(&(_sc)->fv_mtx) +#define FV_UNLOCK(_sc) mtx_unlock(&(_sc)->fv_mtx) +#define FV_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->fv_mtx, MA_OWNED) + +/* + * register space access macros + */ +#define CSR_WRITE_4(sc, reg, val) \ + bus_space_write_4(sc->fv_btag, sc->fv_bhandle, reg, val) + +#define CSR_READ_4(sc, reg) \ + bus_space_read_4(sc->fv_btag, sc->fv_bhandle, reg) + + +/* $NetBSD: aereg.h,v 1.2 2008/04/28 20:23:28 martin Exp $ */ + +/*- + * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 SOFTWFV 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 FV 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 SOFTWFV, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Descriptor Status bits common to transmit and receive. + */ +#define ADSTAT_OWN 0x80000000 /* Tulip owns descriptor */ +#define ADSTAT_ES 0x00008000 /* Error Summary */ + +/* + * Descriptor Status bits for Receive Descriptor. + */ +#define ADSTAT_Rx_FF 0x40000000 /* Filtering Fail */ +#define ADSTAT_Rx_FL 0x3fff0000 /* Frame Length including CRC */ +#define ADSTAT_Rx_DE 0x00004000 /* Descriptor Error */ +#define ADSTAT_Rx_LE 0x00001000 /* Length Error */ +#define ADSTAT_Rx_RF 0x00000800 /* Runt Frame */ +#define ADSTAT_Rx_MF 0x00000400 /* Multicast Frame */ +#define ADSTAT_Rx_FS 0x00000200 /* First Descriptor */ +#define ADSTAT_Rx_LS 0x00000100 /* Last Descriptor */ +#define ADSTAT_Rx_TL 0x00000080 /* Frame Too Long */ +#define ADSTAT_Rx_CS 0x00000040 /* Collision Seen */ +#define ADSTAT_Rx_RT 0x00000020 /* Frame Type */ +#define ADSTAT_Rx_RW 0x00000010 /* Receive Watchdog */ +#define ADSTAT_Rx_RE 0x00000008 /* Report on MII Error */ +#define ADSTAT_Rx_DB 0x00000004 /* Dribbling Bit */ +#define ADSTAT_Rx_CE 0x00000002 /* CRC Error */ +#define ADSTAT_Rx_ZER 0x00000001 /* Zero (always 0) */ + +#define ADSTAT_Rx_LENGTH(x) (((x) & ADSTAT_Rx_FL) >> 16) + +/* + * Descriptor Status bits for Transmit Descriptor. + */ +#define ADSTAT_Tx_ES 0x00008000 /* Error Summary */ +#define ADSTAT_Tx_TO 0x00004000 /* Transmit Jabber Timeout */ +#define ADSTAT_Tx_LO 0x00000800 /* Loss of Carrier */ +#define ADSTAT_Tx_NC 0x00000400 /* No Carrier */ +#define ADSTAT_Tx_LC 0x00000200 /* Late Collision */ +#define ADSTAT_Tx_EC 0x00000100 /* Excessive Collisions */ +#define ADSTAT_Tx_HF 0x00000080 /* Heartbeat Fail */ +#define ADSTAT_Tx_CC 0x00000078 /* Collision Count */ +#define ADSTAT_Tx_ED 0x00000004 /* Excessive Deferral */ +#define ADSTAT_Tx_UF 0x00000002 /* Underflow Error */ +#define ADSTAT_Tx_DE 0x00000001 /* Deferred */ + +#define ADSTAT_Tx_COLLISIONS(x) (((x) & ADSTAT_Tx_CC) >> 3) + +/* + * Descriptor Control bits common to transmit and receive. + */ +#define ADCTL_SIZE1 0x000007ff /* Size of buffer 1 */ +#define ADCTL_SIZE1_SHIFT 0 + +#define ADCTL_SIZE2 0x003ff800 /* Size of buffer 2 */ +#define ADCTL_SIZE2_SHIFT 11 + +#define ADCTL_ER 0x02000000 /* End of Ring */ +#define ADCTL_CH 0x01000000 /* Second Address Chained */ + +/* + * Descriptor Control bits for Transmit Descriptor. + */ +#define ADCTL_Tx_IC 0x80000000 /* Interrupt on Completion */ +#define ADCTL_Tx_LS 0x40000000 /* Last Segment */ +#define ADCTL_Tx_FS 0x20000000 /* First Segment */ +#define ADCTL_Tx_SETUP 0x08000000 /* Setup frame */ +#define ADCTL_Tx_AC 0x04000000 /* Add CRC Disable */ +#define ADCTL_Tx_DPD 0x00800000 /* Disabled Padding */ + +/* + * Control registers. + */ + +/* tese are registers only found on this part */ +#ifdef NOTUSE +#define CSR_MACCTL 0x0000 /* mac control */ +#define CSR_MACHI 0x0004 +#define CSR_MACLO 0x0008 +#define CSR_HTHI 0x000C /* multicast table high */ +#define CSR_HTLO 0x0010 /* multicast table low */ +#define CSR_MIIADDR 0x0014 /* mii address */ +#define CSR_MIIDATA 0x0018 /* mii data */ +#define CSR_FLOWC 0x001C /* flow control */ +#define CSR_VL1 0x0020 /* vlan 1 tag */ +#endif + +/* these are more or less normal Tulip registers */ +#define CSR_BUSMODE (0x08*0) /* bus mode */ +#define CSR_TXPOLL (0x08*1) /* tx poll demand */ +#define CSR_RXPOLL (0x08*2) /* rx poll demand */ +#define CSR_RXLIST (0x08*3) /* rx base descriptor address */ +#define CSR_TXLIST (0x08*4) /* tx base descriptor address */ +#define CSR_STATUS (0x08*5) /* (interrupt) status */ +#define CSR_OPMODE (0x08*6) /* operation mode */ +#define CSR_INTEN (0x08*7) /* interrupt enable */ +#define CSR_MISSED (0x08*8) /* missed frame counter */ + +#ifdef NOTUSE +#define CSR_HTBA 0x1050 /* host tx buffer address (ro) */ +#define CSR_HRBA 0x1054 /* host rx buffer address (ro) */ +#endif + +#define CSR_MIIMNG (0x08*9) /* MII Management Register */ +#define CSR_FULLDUP (0x08*11) /* Full Duplex Register */ + +/* 21143 like register */ +#define FULLDUP_CS 0x80000000 /* Cycle Size */ +#define FULLDUP_TT_SHIFT 27 /* Transmit Timer */ +#define FULLDUP_NTP_SHIFT 24 /* Number of Transmit Packets */ +#define FULLDUP_RT_SHIFT 20 /* Receive Timer */ +#define FULLDUP_NRP_SHIFT 17 /* Number of Receive Packets */ +#define FULLDUP_CON_MODE 0x00010000 /* Continuous Mode */ +#define FULLDUP_TIM_SHIFT 0 /* Timer Value */ + +/* CSR_MACCTL - Mac Control */ +#define MACCTL_RE 0x00000004 /* rx enable */ +#define MACCTL_TE 0x00000008 /* tx enable */ +#define MACCTL_DC 0x00000020 /* deferral check */ +#define MACCTL_PSTR 0x00000100 /* automatic pad strip */ +#define MACCTL_DTRY 0x00000400 /* disable retry */ +#define MACCTL_DBF 0x00000800 /* disable broadcast frames */ +#define MACCTL_LCC 0x00001000 /* late collision control */ +#define MACCTL_HASH 0x00002000 /* hash filtering enable */ +#define MACCTL_HO 0x00008000 /* disable perfect filtering */ +#define MACCTL_PB 0x00010000 /* pass bad frames */ +#define MACCTL_IF 0x00020000 /* inverse filtering */ +#define MACCTL_PR 0x00040000 /* promiscuous mode */ +#define MACCTL_PM 0x00080000 /* pass all multicast */ +#define MACCTL_FDX 0x00100000 /* full duplex mode */ +#define MACCTL_LOOP 0x00600000 /* loopback mask */ +#define MACCTL_LOOP_INT 0x00200000 /* internal loopback */ +#define MACCTL_LOOP_EXT 0x00400000 /* external loopback */ +#define MACCTL_LOOP_NONE 0x00000000 +#define MACCTL_DRO 0x00800000 /* disable receive own */ +#define MACCTL_PS 0x08000000 /* port select, 0 = mii */ +#define MACCTL_HBD 0x10000000 /* heartbeat disable */ +#define MACCTL_BLE 0x40000000 /* mac big endian */ +#define MACCTL_RA 0x80000000 /* receive all packets */ + +/* CSR_MIIADDR - MII Addess */ +#define MIIADDR_BUSY 0x00000001 /* mii busy */ +#define MIIADDR_WRITE 0x00000002 /* mii write */ +#define MIIADDR_REG_MASK 0x000007C0 /* mii register */ +#define MIIADDR_REG_SHIFT 6 +#define MIIADDR_PHY_MASK 0x0000F800 /* mii phy */ +#define MIIADDR_PHY_SHIFT 11 + +#define MIIADDR_GETREG(x) (((x) & MIIADDR_REG) >> 6) +#define MIIADDR_PUTREG(x) (((x) << 6) & MIIADR_REG) +#define MIIADDR_GETPHY(x) (((x) & MIIADDR_PHY) >> 11) +#define MIIADDR_PUTPHY(x) (((x) << 6) & MIIADR_PHY) + +/* CSR_FLOWC - Flow Control */ +#define FLOWC_FCB 0x00000001 /* flow control busy */ +#define FLOWC_FCE 0x00000002 /* flow control enable */ +#define FLOWC_PCF 0x00000004 /* pass control frames */ +#define FLOWC_PT 0xffff0000 /* pause time */ + +/* CSR_BUSMODE - Bus Mode */ +#define BUSMODE_SWR 0x00000001 /* software reset */ +#define BUSMODE_BAR 0x00000002 /* bus arbitration */ +#define BUSMODE_DSL 0x0000007c /* descriptor skip length */ +#define BUSMODE_BLE 0x00000080 /* data buf endian */ + /* programmable burst length */ +#define BUSMODE_PBL_DEFAULT 0x00000000 /* default value */ +#define BUSMODE_PBL_1LW 0x00000100 /* 1 longword */ +#define BUSMODE_PBL_2LW 0x00000200 /* 2 longwords */ +#define BUSMODE_PBL_4LW 0x00000400 /* 4 longwords */ +#define BUSMODE_PBL_8LW 0x00000800 /* 8 longwords */ +#define BUSMODE_PBL_16LW 0x00001000 /* 16 longwords */ +#define BUSMODE_PBL_32LW 0x00002000 /* 32 longwords */ +#define BUSMODE_TAP_SHIFT 17 /* Transmit Automatic Polling */ +#define BUSMODE_DBO 0x00100000 /* descriptor endian */ +#define BUSMODE_ALIGN_16B 0x01000000 /* force oddhw rx buf align */ + +/* CSR_TXPOLL - Transmit Poll Demand */ +#define TXPOLL_TPD 0x00000001 /* transmit poll demand */ + + +/* CSR_RXPOLL - Receive Poll Demand */ +#define RXPOLL_RPD 0x00000001 /* receive poll demand */ + +/* CSR_STATUS - Status */ +#define STATUS_TI 0x00000001 /* transmit interrupt */ +#define STATUS_TPS 0x00000002 /* transmit process stopped */ +#define STATUS_TU 0x00000004 /* transmit buffer unavail */ +#define STATUS_TJT 0x00000008 /* transmit jabber timeout */ +#define STATUS_UNF 0x00000020 /* transmit underflow */ +#define STATUS_RI 0x00000040 /* receive interrupt */ +#define STATUS_RU 0x00000080 /* receive buffer unavail */ +#define STATUS_RPS 0x00000100 /* receive process stopped */ +#define STATUS_ETI 0x00000400 /* early transmit interrupt */ +#define STATUS_SE 0x00002000 /* system error */ +#define STATUS_ER 0x00004000 /* early receive (21041) */ +#define STATUS_AIS 0x00008000 /* abnormal intr summary */ +#define STATUS_NIS 0x00010000 /* normal interrupt summary */ +#define STATUS_RS 0x000e0000 /* receive process state */ +#define STATUS_RS_STOPPED 0x00000000 /* Stopped */ +#define STATUS_RS_FETCH 0x00020000 /* Running - fetch receive + descriptor */ +#define STATUS_RS_CHECK 0x00040000 /* Running - check for end + of receive */ +#define STATUS_RS_WAIT 0x00060000 /* Running - wait for packet */ +#define STATUS_RS_SUSPENDED 0x00080000 /* Suspended */ +#define STATUS_RS_CLOSE 0x000a0000 /* Running - close receive + descriptor */ +#define STATUS_RS_FLUSH 0x000c0000 /* Running - flush current + frame from FIFO */ +#define STATUS_RS_QUEUE 0x000e0000 /* Running - queue current + frame from FIFO into + buffer */ +#define STATUS_TS 0x00700000 /* transmit process state */ +#define STATUS_TS_STOPPED 0x00000000 /* Stopped */ +#define STATUS_TS_FETCH 0x00100000 /* Running - fetch transmit + descriptor */ +#define STATUS_TS_WAIT 0x00200000 /* Running - wait for end + of transmission */ +#define STATUS_TS_READING 0x00300000 /* Running - read buffer from + memory and queue into + FIFO */ +#define STATUS_TS_SUSPENDED 0x00600000 /* Suspended */ +#define STATUS_TS_CLOSE 0x00700000 /* Running - close transmit + descriptor */ +#define STATUS_TX_ABORT 0x00800000 /* Transmit bus abort */ +#define STATUS_RX_ABORT 0x01000000 /* Transmit bus abort */ + +/* CSR_OPMODE - Operation Mode */ +#define OPMODE_SR 0x00000002 /* start receive */ +#define OPMODE_OSF 0x00000004 /* operate on second frame */ +#define OPMODE_PR 0x00000040 /* promiscuous mode */ +#define OPMODE_PM 0x00000080 /* pass all multicast */ +#define OPMODE_FDX 0x00000200 /* full duplex mode */ +#define OPMODE_ST 0x00002000 /* start transmitter */ +#define OPMODE_TR 0x0000c000 /* threshold control */ +#define OPMODE_TR_32 0x00000000 /* 32 words */ +#define OPMODE_TR_64 0x00004000 /* 64 words */ +#define OPMODE_TR_128 0x00008000 /* 128 words */ +#define OPMODE_TR_256 0x0000c000 /* 256 words */ +#define OPMODE_SF 0x00200000 /* store and forward mode */ +#define OPMODE_SPEED 0x80000000 /* speed 100M:1 10M:0 */ + +/* CSR_INTEN - Interrupt Enable */ + /* See bits for CSR_STATUS -- Status */ + + +/* CSR_MISSED - Missed Frames */ +#define MISSED_MFC 0xffff0000 /* missed packet count */ +#define MISSED_FOC 0x0000ffff /* fifo overflow counter */ + +#define MISSED_GETMFC(x) ((x) & MISSED_MFC) +#define MISSED_GETFOC(x) (((x) & MISSED_FOC) >> 16) + +/* setup frame code refer dc code */ + +#define FV_SFRAME_LEN 192 +#define FV_MIN_FRAMELEN 60 + +/* + * MII Definitions for the 21041 and 21140/21140A/21142 + * copy from if_devar.h + */ +#define MII_PREAMBLE (~0) +#define MII_TEST 0xAAAAAAAA +#define MII_RDCMD 0x06 +#define MII_WRCMD 0x05 +#define MII_DIN 0x00080000 +#define MII_RD 0x00040000 +#define MII_WR 0x00000000 +#define MII_DOUT 0x00020000 +#define MII_CLK 0x00010000 +#define MII_CLKON MII_CLK +#define MII_CLKOFF MII_CLK + +#endif /* __IF_FVREG_H__ */ Property changes on: head/sys/arm/ralink/if_fvreg.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ralink/rt1310_gpio.c =================================================================== --- head/sys/arm/ralink/rt1310_gpio.c (nonexistent) +++ head/sys/arm/ralink/rt1310_gpio.c (revision 317872) @@ -0,0 +1,480 @@ +/*- + * Copyright (c) 2011 Jakub Wojciech Klama + * Copyright (c) 2015 Hiroki Mori + * 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. + * + */ + +/* + * GPIO on RT1310A consist of 2 ports: + * - PortA with 8 input/output pins + * - PortB with 4 input/output pins + * + * Pins are mapped to logical pin number as follows: + * [0..7] -> GPI_00..GPI_07 (port A) + * [8..11] -> GPI_08..GPI_11 (port B) + * + */ + + +#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 + +#include +#include +#include + +#include +#include + +#include "gpio_if.h" + +struct rt1310_gpio_softc +{ + device_t lg_dev; + device_t lg_busdev; + struct resource * lg_res; + bus_space_tag_t lg_bst; + bus_space_handle_t lg_bsh; +}; + +struct rt1310_gpio_pinmap +{ + int lp_start_idx; + int lp_pin_count; + int lp_port; + int lp_start_bit; + int lp_flags; +}; + +static const struct rt1310_gpio_pinmap rt1310_gpio_pins[] = { + { 0, 8, RT_GPIO_PORTA, 0, GPIO_PIN_INPUT | GPIO_PIN_OUTPUT }, + { 8, 4, RT_GPIO_PORTB, 0, GPIO_PIN_INPUT | GPIO_PIN_OUTPUT }, + { -1, -1, -1, -1, -1 }, +}; + +#define RT_GPIO_NPINS 12 + +#define RT_GPIO_PIN_IDX(_map, _idx) \ + (_idx - _map->lp_start_idx) + +#define RT_GPIO_PIN_BIT(_map, _idx) \ + (_map->lp_start_bit + RT_GPIO_PIN_IDX(_map, _idx)) + +static int rt1310_gpio_probe(device_t); +static int rt1310_gpio_attach(device_t); +static int rt1310_gpio_detach(device_t); + +static device_t rt1310_gpio_get_bus(device_t); +static int rt1310_gpio_pin_max(device_t, int *); +static int rt1310_gpio_pin_getcaps(device_t, uint32_t, uint32_t *); +static int rt1310_gpio_pin_getflags(device_t, uint32_t, uint32_t *); +static int rt1310_gpio_pin_setflags(device_t, uint32_t, uint32_t); +static int rt1310_gpio_pin_getname(device_t, uint32_t, char *); +static int rt1310_gpio_pin_get(device_t, uint32_t, uint32_t *); +static int rt1310_gpio_pin_set(device_t, uint32_t, uint32_t); +static int rt1310_gpio_pin_toggle(device_t, uint32_t); + +static const struct rt1310_gpio_pinmap *rt1310_gpio_get_pinmap(int); + +static struct rt1310_gpio_softc *rt1310_gpio_sc = NULL; + +#define rt1310_gpio_read_4(_sc, _reg) \ + bus_space_read_4(_sc->lg_bst, _sc->lg_bsh, _reg) +#define rt1310_gpio_write_4(_sc, _reg, _val) \ + bus_space_write_4(_sc->lg_bst, _sc->lg_bsh, _reg, _val) + +static int +rt1310_gpio_probe(device_t dev) +{ + phandle_t node; + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ralink,rt1310-gpio")) + return (ENXIO); + + node = ofw_bus_get_node(dev); + if (!OF_hasprop(node, "gpio-controller")) + return (ENXIO); + + device_set_desc(dev, "RT1310 GPIO"); + return (BUS_PROBE_DEFAULT); +} + +static int +rt1310_gpio_attach(device_t dev) +{ + struct rt1310_gpio_softc *sc = device_get_softc(dev); + int rid; + + sc->lg_dev = dev; + + rid = 0; + sc->lg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (!sc->lg_res) { + device_printf(dev, "cannot allocate memory window\n"); + return (ENXIO); + } + + sc->lg_bst = rman_get_bustag(sc->lg_res); + sc->lg_bsh = rman_get_bushandle(sc->lg_res); + + rt1310_gpio_sc = sc; + + sc->lg_busdev = gpiobus_attach_bus(dev); + if (sc->lg_busdev == NULL) { + bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->lg_res); + return (ENXIO); + } + + return (0); +} + +static int +rt1310_gpio_detach(device_t dev) +{ + return (EBUSY); +} + +static device_t +rt1310_gpio_get_bus(device_t dev) +{ + struct rt1310_gpio_softc *sc; + + sc = device_get_softc(dev); + + return (sc->lg_busdev); +} + +static int +rt1310_gpio_pin_max(device_t dev, int *npins) +{ + *npins = RT_GPIO_NPINS - 1; + return (0); +} + +static int +rt1310_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) +{ + const struct rt1310_gpio_pinmap *map; + + if (pin > RT_GPIO_NPINS) + return (ENODEV); + + map = rt1310_gpio_get_pinmap(pin); + + *caps = map->lp_flags; + return (0); +} + +static int +rt1310_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) +{ + struct rt1310_gpio_softc *sc = device_get_softc(dev); + const struct rt1310_gpio_pinmap *map; + uint32_t state; + int dir; + + if (pin > RT_GPIO_NPINS) + return (ENODEV); + + map = rt1310_gpio_get_pinmap(pin); + + /* Check whether it's bidirectional pin */ + if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) != + (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) { + *flags = map->lp_flags; + return (0); + } + + switch (map->lp_port) { + case RT_GPIO_PORTA: + state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PADIR); + dir = (state & (1 << RT_GPIO_PIN_BIT(map, pin))); + break; + case RT_GPIO_PORTB: + state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PBDIR); + dir = (state & (1 << RT_GPIO_PIN_BIT(map, pin))); + break; + default: + panic("unknown GPIO port"); + } + + *flags = dir ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT; + + return (0); +} + +static int +rt1310_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) +{ + struct rt1310_gpio_softc *sc = device_get_softc(dev); + const struct rt1310_gpio_pinmap *map; + uint32_t dir, state; + uint32_t port; + + if (pin > RT_GPIO_NPINS) + return (ENODEV); + + map = rt1310_gpio_get_pinmap(pin); + + /* Check whether it's bidirectional pin */ + if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) != + (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) + return (ENOTSUP); + + if (flags & GPIO_PIN_INPUT) + dir = 0; + + if (flags & GPIO_PIN_OUTPUT) + dir = 1; + + switch (map->lp_port) { + case RT_GPIO_PORTA: + port = RT_GPIO_OFF_PADIR; + break; + case RT_GPIO_PORTB: + port = RT_GPIO_OFF_PBDIR; + break; + } + + state = rt1310_gpio_read_4(sc, port); + if (flags & GPIO_PIN_INPUT) { + state &= ~(1 << RT_GPIO_PIN_IDX(map, pin)); + } else { + state |= (1 << RT_GPIO_PIN_IDX(map, pin)); + } + rt1310_gpio_write_4(sc, port, state); + + return (0); +} + +static int +rt1310_gpio_pin_getname(device_t dev, uint32_t pin, char *name) +{ + snprintf(name, GPIOMAXNAME - 1, "GPIO_%02d", pin); + + return (0); +} + +static int +rt1310_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *value) +{ + struct rt1310_gpio_softc *sc = device_get_softc(dev); + const struct rt1310_gpio_pinmap *map; + uint32_t state, flags; + int dir; + + map = rt1310_gpio_get_pinmap(pin); + + if (rt1310_gpio_pin_getflags(dev, pin, &flags)) + return (ENXIO); + + if (flags & GPIO_PIN_OUTPUT) + dir = 1; + + if (flags & GPIO_PIN_INPUT) + dir = 0; + + switch (map->lp_port) { + case RT_GPIO_PORTA: + state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PADR); + *value = !!(state & (1 << RT_GPIO_PIN_BIT(map, pin))); + break; + case RT_GPIO_PORTB: + state = rt1310_gpio_read_4(sc, RT_GPIO_OFF_PBDR); + *value = !!(state & (1 << RT_GPIO_PIN_BIT(map, pin))); + break; + } + + return (0); +} + +static int +rt1310_gpio_pin_set(device_t dev, uint32_t pin, uint32_t value) +{ + struct rt1310_gpio_softc *sc = device_get_softc(dev); + const struct rt1310_gpio_pinmap *map; + uint32_t state, flags; + uint32_t port; + + map = rt1310_gpio_get_pinmap(pin); + + if (rt1310_gpio_pin_getflags(dev, pin, &flags)) + return (ENXIO); + + if ((flags & GPIO_PIN_OUTPUT) == 0) + return (EINVAL); + + switch (map->lp_port) { + case RT_GPIO_PORTA: + port = RT_GPIO_OFF_PADR; + break; + case RT_GPIO_PORTB: + port = RT_GPIO_OFF_PBDR; + break; + } + + state = rt1310_gpio_read_4(sc, port); + if (value == 1) { + state |= (1 << RT_GPIO_PIN_BIT(map, pin)); + } else { + state &= ~(1 << RT_GPIO_PIN_BIT(map, pin)); + } + rt1310_gpio_write_4(sc, port, state); + + return (0); +} + +static int +rt1310_gpio_pin_toggle(device_t dev, uint32_t pin) +{ + const struct rt1310_gpio_pinmap *map; + uint32_t flags; + + map = rt1310_gpio_get_pinmap(pin); + + if (rt1310_gpio_pin_getflags(dev, pin, &flags)) + return (ENXIO); + + if ((flags & GPIO_PIN_OUTPUT) == 0) + return (EINVAL); + + panic("not implemented yet"); + + return (0); + +} + +static const struct rt1310_gpio_pinmap * +rt1310_gpio_get_pinmap(int pin) +{ + const struct rt1310_gpio_pinmap *map; + + for (map = &rt1310_gpio_pins[0]; map->lp_start_idx != -1; map++) { + if (pin >= map->lp_start_idx && + pin < map->lp_start_idx + map->lp_pin_count) + return map; + } + + panic("pin number %d out of range", pin); +} + +int +rt1310_gpio_set_flags(device_t dev, int pin, int flags) +{ + if (rt1310_gpio_sc == NULL) + return (ENXIO); + + return rt1310_gpio_pin_setflags(rt1310_gpio_sc->lg_dev, pin, flags); +} + +int +rt1310_gpio_set_state(device_t dev, int pin, int state) +{ + if (rt1310_gpio_sc == NULL) + return (ENXIO); + + return rt1310_gpio_pin_set(rt1310_gpio_sc->lg_dev, pin, state); +} + +int +rt1310_gpio_get_state(device_t dev, int pin, int *state) +{ + if (rt1310_gpio_sc == NULL) + return (ENXIO); + + return rt1310_gpio_pin_get(rt1310_gpio_sc->lg_dev, pin, state); +} + +static phandle_t +rt1310_gpio_get_node(device_t bus, device_t dev) +{ + /* We only have one child, the GPIO bus, which needs our own node. */ + return (ofw_bus_get_node(bus)); +} + +static device_method_t rt1310_gpio_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rt1310_gpio_probe), + DEVMETHOD(device_attach, rt1310_gpio_attach), + DEVMETHOD(device_detach, rt1310_gpio_detach), + + /* GPIO interface */ + DEVMETHOD(gpio_get_bus, rt1310_gpio_get_bus), + DEVMETHOD(gpio_pin_max, rt1310_gpio_pin_max), + DEVMETHOD(gpio_pin_getcaps, rt1310_gpio_pin_getcaps), + DEVMETHOD(gpio_pin_getflags, rt1310_gpio_pin_getflags), + DEVMETHOD(gpio_pin_setflags, rt1310_gpio_pin_setflags), + DEVMETHOD(gpio_pin_getname, rt1310_gpio_pin_getname), + DEVMETHOD(gpio_pin_set, rt1310_gpio_pin_set), + DEVMETHOD(gpio_pin_get, rt1310_gpio_pin_get), + DEVMETHOD(gpio_pin_toggle, rt1310_gpio_pin_toggle), + + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_node, rt1310_gpio_get_node), + + { 0, 0 } +}; + +static devclass_t rt1310_gpio_devclass; + +static driver_t rt1310_gpio_driver = { + "gpio", + rt1310_gpio_methods, + sizeof(struct rt1310_gpio_softc), +}; + +DRIVER_MODULE(rt1310gpio, simplebus, rt1310_gpio_driver, rt1310_gpio_devclass, 0, 0); +MODULE_VERSION(rt1310gpio, 1); Property changes on: head/sys/arm/ralink/rt1310_gpio.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ralink/rt1310_intc.c =================================================================== --- head/sys/arm/ralink/rt1310_intc.c (nonexistent) +++ head/sys/arm/ralink/rt1310_intc.c (revision 317872) @@ -0,0 +1,441 @@ +/*- + * Copyright (c) 2010 Jakub Wojciech Klama + * Copyright (c) 2015 Hiroki Mori + * 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 +__FBSDID("$FreeBSD$"); + +#include "opt_platform.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _ARM32_BUS_DMA_PRIVATE +#include +#include + +#include +#include + +#include +#include + +#include + +#define INTC_NIRQS 32 + +#ifdef INTRNG +#include "pic_if.h" + +struct rt1310_irqsrc { + struct intr_irqsrc ri_isrc; + u_int ri_irq; +}; +#endif + +struct rt1310_intc_softc { + device_t dev; + struct resource * ri_res; + bus_space_tag_t ri_bst; + bus_space_handle_t ri_bsh; +#ifdef INTRNG + struct rt1310_irqsrc ri_isrcs[INTC_NIRQS]; +#endif +}; + +static int rt1310_intc_probe(device_t); +static int rt1310_intc_attach(device_t); +#ifndef INTRNG +static void rt1310_intc_eoi(void *); +#else +static int rt1310_pic_attach(struct rt1310_intc_softc *sc); +#endif + +static struct rt1310_intc_softc *intc_softc = NULL; + +#define intc_read_4(_sc, _reg) \ + bus_space_read_4((_sc)->ri_bst, (_sc)->ri_bsh, (_reg)) +#define intc_write_4(_sc, _reg, _val) \ + bus_space_write_4((_sc)->ri_bst, (_sc)->ri_bsh, (_reg), (_val)) + +struct rt1310_irqdef { + u_int ri_trig; + u_int ri_prio; +}; + +struct rt1310_irqdef irqdef[INTC_NIRQS] = { + {RT_INTC_TRIG_HIGH_LVL, 2}, /* 0 */ + {RT_INTC_TRIG_HIGH_LVL, 2}, + {RT_INTC_TRIG_HIGH_LVL, 2}, + {RT_INTC_TRIG_HIGH_LVL, 1}, + {RT_INTC_TRIG_HIGH_LVL, 2}, + {RT_INTC_TRIG_HIGH_LVL, 1}, + {RT_INTC_TRIG_HIGH_LVL, 1}, + {RT_INTC_TRIG_HIGH_LVL, 1}, + {RT_INTC_TRIG_HIGH_LVL, 1}, /* 8 */ + {RT_INTC_TRIG_HIGH_LVL, 1}, + {RT_INTC_TRIG_HIGH_LVL, 2}, + {RT_INTC_TRIG_LOW_LVL, 2}, + {RT_INTC_TRIG_LOW_LVL, 2}, + {RT_INTC_TRIG_LOW_LVL, 4}, + {RT_INTC_TRIG_HIGH_LVL, 2}, + {RT_INTC_TRIG_HIGH_LVL, 2}, + {RT_INTC_TRIG_HIGH_LVL, 2}, /* 16 */ + {RT_INTC_TRIG_HIGH_LVL, 2}, + {RT_INTC_TRIG_LOW_LVL, 2}, + {RT_INTC_TRIG_LOW_LVL, 2}, + {RT_INTC_TRIG_LOW_LVL, 2}, + {RT_INTC_TRIG_LOW_LVL, 2}, + {RT_INTC_TRIG_NEG_EDGE, 2}, + {RT_INTC_TRIG_HIGH_LVL, 3}, + {RT_INTC_TRIG_HIGH_LVL, 2}, /* 24 */ + {RT_INTC_TRIG_POS_EDGE, 2}, + {RT_INTC_TRIG_POS_EDGE, 2}, + {RT_INTC_TRIG_HIGH_LVL, 2}, + {RT_INTC_TRIG_HIGH_LVL, 2}, + {RT_INTC_TRIG_POS_EDGE, 2}, + {RT_INTC_TRIG_POS_EDGE, 3}, + {RT_INTC_TRIG_POS_EDGE, 3}, +}; + +static int +rt1310_intc_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "rt,pic")) + return (ENXIO); + +#ifdef INTRNG + device_set_desc(dev, "RT1310 INTRNG Interrupt Controller"); +#else + device_set_desc(dev, "RT1310 Interrupt Controller"); +#endif + return (BUS_PROBE_DEFAULT); +} + +static int +rt1310_intc_attach(device_t dev) +{ + struct rt1310_intc_softc *sc = device_get_softc(dev); + int rid = 0; + int i; + + if (intc_softc) + return (ENXIO); + + sc->dev = dev; + + sc->ri_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (!sc->ri_res) { + device_printf(dev, "could not alloc resources\n"); + return (ENXIO); + } + + sc->ri_bst = rman_get_bustag(sc->ri_res); + sc->ri_bsh = rman_get_bushandle(sc->ri_res); + intc_softc = sc; +#ifndef INTRNG + arm_post_filter = rt1310_intc_eoi; +#else + rt1310_pic_attach(sc); +#endif + + intc_write_4(sc, RT_INTC_IECR, 0); + intc_write_4(sc, RT_INTC_ICCR, ~0); + + for (i = 0; i <= INTC_NIRQS; ++i) { + intc_write_4(sc, RT_INTC_SCR0+i*4, + (irqdef[i].ri_trig << RT_INTC_TRIG_SHIF) | + irqdef[i].ri_prio); + intc_write_4(sc, RT_INTC_SVR0+i*4, i); + } + + /* Clear interrupt status registers and disable all interrupts */ + intc_write_4(sc, RT_INTC_ICCR, ~0); + intc_write_4(sc, RT_INTC_IMR, 0); + return (0); +} + +#ifndef INTRNG +int +arm_get_next_irq(int last) +{ + struct rt1310_intc_softc *sc = intc_softc; + uint32_t value; + int i; + value = intc_read_4(sc, RT_INTC_IPR); + for (i = 0; i < 32; i++) { + if (value & (1 << i)) + return (i); + } + + return (-1); +} + +void +arm_mask_irq(uintptr_t nb) +{ + struct rt1310_intc_softc *sc = intc_softc; + uint32_t value; + + /* Make sure that interrupt isn't active already */ + rt1310_intc_eoi((void *)nb); + + /* Clear bit in ER register */ + value = intc_read_4(sc, RT_INTC_IECR); + value &= ~(1 << nb); + intc_write_4(sc, RT_INTC_IECR, value); + intc_write_4(sc, RT_INTC_IMR, value); + + intc_write_4(sc, RT_INTC_ICCR, 1 << nb); +} + +void +arm_unmask_irq(uintptr_t nb) +{ + struct rt1310_intc_softc *sc = intc_softc; + uint32_t value; + + value = intc_read_4(sc, RT_INTC_IECR); + + value |= (1 << nb); + + intc_write_4(sc, RT_INTC_IMR, value); + intc_write_4(sc, RT_INTC_IECR, value); +} + +static void +rt1310_intc_eoi(void *data) +{ + struct rt1310_intc_softc *sc = intc_softc; + int nb = (int)data; + + intc_write_4(sc, RT_INTC_ICCR, 1 << nb); + if (nb == 0) { + uint32_t value; + value = intc_read_4(sc, RT_INTC_IECR); + value &= ~(1 << nb); + intc_write_4(sc, RT_INTC_IECR, value); + intc_write_4(sc, RT_INTC_IMR, value); + } +} + +#else + +static void +rt1310_enable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + u_int irq; + unsigned int value; + struct rt1310_intc_softc *sc; + + sc = intc_softc; + irq = ((struct rt1310_irqsrc *)isrc)->ri_irq; + + value = intc_read_4(sc, RT_INTC_IECR); + + value |= (1 << irq); + + intc_write_4(sc, RT_INTC_IMR, value); + intc_write_4(sc, RT_INTC_IECR, value); +} + +static void +rt1310_disable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + u_int irq; + unsigned int value; + struct rt1310_intc_softc *sc; + + sc = intc_softc; + irq = ((struct rt1310_irqsrc *)isrc)->ri_irq; + + /* Clear bit in ER register */ + value = intc_read_4(sc, RT_INTC_IECR); + value &= ~(1 << irq); + intc_write_4(sc, RT_INTC_IECR, value); + intc_write_4(sc, RT_INTC_IMR, value); + + intc_write_4(sc, RT_INTC_ICCR, 1 << irq); +} + +static int +rt1310_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) +{ + struct intr_map_data_fdt *daf; + struct rt1310_intc_softc *sc; + + if (data->type != INTR_MAP_DATA_FDT) + return (ENOTSUP); + + daf = (struct intr_map_data_fdt *)data; + + if (daf->ncells != 1 || daf->cells[0] >= INTC_NIRQS) + return (EINVAL); + + sc = device_get_softc(dev); + *isrcp = &sc->ri_isrcs[daf->cells[0]].ri_isrc; + return (0); +} + +static void +rt1310_pre_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + arm_irq_memory_barrier(0); + rt1310_disable_intr(dev, isrc); +} + +static void +rt1310_post_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + arm_irq_memory_barrier(0); + rt1310_enable_intr(dev, isrc); +} + +static void +rt1310_post_filter(device_t dev, struct intr_irqsrc *isrc) +{ + u_int irq; + struct rt1310_intc_softc *sc; + + arm_irq_memory_barrier(0); + sc = intc_softc; + irq = ((struct rt1310_irqsrc *)isrc)->ri_irq; + + intc_write_4(sc, RT_INTC_ICCR, 1 << irq); +} + +static int +rt1310_intr(void *arg) +{ + uint32_t irq; + struct rt1310_intc_softc *sc = arg; + + irq = ffs(intc_read_4(sc, RT_INTC_IPR)) - 1; + + if (intr_isrc_dispatch(&sc->ri_isrcs[irq].ri_isrc, + curthread->td_intr_frame) != 0) { + intc_write_4(sc, RT_INTC_ICCR, 1 << irq); + device_printf(sc->dev, "Stray irq %u disabled\n", irq); + } + + arm_irq_memory_barrier(0); + + return (FILTER_HANDLED); +} + +static int +rt1310_pic_attach(struct rt1310_intc_softc *sc) +{ + struct intr_pic *pic; + int error; + uint32_t irq; + const char *name; + intptr_t xref; + + name = device_get_nameunit(sc->dev); + for (irq = 0; irq < INTC_NIRQS; irq++) { + sc->ri_isrcs[irq].ri_irq = irq; + + error = intr_isrc_register(&sc->ri_isrcs[irq].ri_isrc, + sc->dev, 0, "%s,%u", name, irq); + if (error != 0) + return (error); + } + + xref = OF_xref_from_node(ofw_bus_get_node(sc->dev)); + pic = intr_pic_register(sc->dev, xref); + if (pic == NULL) + return (ENXIO); + + return (intr_pic_claim_root(sc->dev, xref, rt1310_intr, sc, 0)); +} +#endif + +struct fdt_fixup_entry fdt_fixup_table[] = { + { NULL, NULL } +}; + +#ifndef INTRNG +static int +fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, + int *pol) +{ + if (!fdt_is_compatible(node, "lpc,pic")) + return (ENXIO); + + *interrupt = fdt32_to_cpu(intr[0]); + *trig = INTR_TRIGGER_CONFORM; + *pol = INTR_POLARITY_CONFORM; + return (0); +} + +fdt_pic_decode_t fdt_pic_table[] = { + &fdt_pic_decode_ic, + NULL +}; +#endif + +static device_method_t rt1310_intc_methods[] = { + DEVMETHOD(device_probe, rt1310_intc_probe), + DEVMETHOD(device_attach, rt1310_intc_attach), +#ifdef INTRNG + DEVMETHOD(pic_disable_intr, rt1310_disable_intr), + DEVMETHOD(pic_enable_intr, rt1310_enable_intr), + DEVMETHOD(pic_map_intr, rt1310_map_intr), + DEVMETHOD(pic_post_filter, rt1310_post_filter), + DEVMETHOD(pic_post_ithread, rt1310_post_ithread), + DEVMETHOD(pic_pre_ithread, rt1310_pre_ithread), +#endif + { 0, 0 } +}; + +static driver_t rt1310_intc_driver = { + "pic", + rt1310_intc_methods, + sizeof(struct rt1310_intc_softc), +}; + +static devclass_t rt1310_intc_devclass; + +EARLY_DRIVER_MODULE(pic, simplebus, rt1310_intc_driver, rt1310_intc_devclass, 0, 0, BUS_PASS_INTERRUPT); Property changes on: head/sys/arm/ralink/rt1310_intc.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ralink/rt1310_machdep.c =================================================================== --- head/sys/arm/ralink/rt1310_machdep.c (nonexistent) +++ head/sys/arm/ralink/rt1310_machdep.c (revision 317872) @@ -0,0 +1,176 @@ +/*- + * Copyright (c) 1994-1998 Mark Brinicombe. + * Copyright (c) 1994 Brini. + * All rights reserved. + * + * This code is derived from software written for Brini by Mark Brinicombe + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Brini. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI 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. + * + * from: FreeBSD: sys/arm/lpc/lpc_machdep.c + */ + +#include "opt_ddb.h" +#include "opt_platform.h" + +#include +__FBSDID("$FreeBSD$"); + +#define _ARM32_BUS_DMA_PRIVATE +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#ifdef EARLY_PRINTF +early_putc_t *early_putc; +#endif + + +uint32_t rt1310_master_clock; + +vm_offset_t +platform_lastaddr(void) +{ + + return (devmap_lastaddr()); +} + +void +platform_probe_and_attach(void) +{ +} + +void +platform_gpio_init(void) +{ + + /* + * Set initial values of GPIO output ports + */ +} + +void +platform_late_init(void) +{ + bootverbose = 1; +} + +/* + * Add a single static device mapping. + * The values used were taken from the ranges property of the SoC node in the + * dts file when this code was converted to arm_devmap_add_entry(). + */ +int +platform_devmap_init(void) +{ + devmap_add_entry(0x19C00000, 0xE0000); + devmap_add_entry(0x1e800000, 0x800000); + devmap_add_entry(0x1f000000, 0x400000); + return (0); +} + +struct arm32_dma_range * +bus_dma_get_range(void) +{ + + return (NULL); +} + +int +bus_dma_get_range_nb(void) +{ + + return (0); +} + +void +cpu_reset(void) +{ + bus_space_tag_t bst; + bus_space_handle_t bsh; + + bst = fdtbus_bs_tag; + + /* Enable WDT */ + /* Instant assert of RESETOUT_N with pulse length 1ms */ + bus_space_map(bst, 0x1e8c0000, 0x20000, 0, &bsh); + bus_space_write_4(bst, bsh, 0, 13000); + bus_space_write_4(bst, bsh, 8, (1<<3) | (1<<4) | 7); + bus_space_unmap(bst, bsh, 0x20000); + + for (;;) + continue; +} + +#ifdef RALINK_BOOT_DEBUG +void bootdebug1(int c); +void bootdebug1(int c) +{ + /* direct put uart physical address */ + uint8_t* uart_base_addr=(uint8_t*)0x1e840000; + *(uart_base_addr) = c; +} + +void bootdebug2(int c); +void bootdebug2(int c) +{ +#if defined(SOCDEV_PA) && defined(SOCDEV_VA) + /* direct put uart map address at locore-v4.S */ + uint8_t* uart_base_addr=(uint8_t*)0xce840000; + *(uart_base_addr) = c; +#endif +} + +void bootdebug3(int c); +void bootdebug3(int c) +{ + bus_space_tag_t bst; + bus_space_handle_t bsh; + + bst = fdtbus_bs_tag; + bus_space_map(bst, 0x1e840000, 0x20000, 0, &bsh); + bus_space_write_1(bst, bsh, 0, c); + bus_space_unmap(bst, bsh, 0x20000); +} +#endif Property changes on: head/sys/arm/ralink/rt1310_machdep.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ralink/rt1310_timer.c =================================================================== --- head/sys/arm/ralink/rt1310_timer.c (nonexistent) +++ head/sys/arm/ralink/rt1310_timer.c (revision 317872) @@ -0,0 +1,341 @@ +/*- + * Copyright (c) 2011 Jakub Wojciech Klama + * Copyright (c) 2015 Hiroki Mori + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +struct rt1310_timer_softc { + device_t lt_dev; + struct eventtimer lt_et; + struct resource * lt_res[8]; + bus_space_tag_t lt_bst0; + bus_space_handle_t lt_bsh0; + bus_space_tag_t lt_bst1; + bus_space_handle_t lt_bsh1; + bus_space_tag_t lt_bst2; + bus_space_handle_t lt_bsh2; + bus_space_tag_t lt_bst3; + bus_space_handle_t lt_bsh3; + int lt_oneshot; + uint32_t lt_period; +}; + +static struct resource_spec rt1310_timer_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_MEMORY, 1, RF_ACTIVE }, + { SYS_RES_MEMORY, 2, RF_ACTIVE }, + { SYS_RES_MEMORY, 3, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 1, RF_ACTIVE }, + { SYS_RES_IRQ, 2, RF_ACTIVE }, + { -1, 0 } +}; + +static struct rt1310_timer_softc *timer_softc = NULL; +static int rt1310_timer_initialized = 0; +static int rt1310_timer_probe(device_t); +static int rt1310_timer_attach(device_t); +static int rt1310_timer_start(struct eventtimer *, + sbintime_t first, sbintime_t period); +static int rt1310_timer_stop(struct eventtimer *et); +static unsigned rt1310_get_timecount(struct timecounter *); +static int rt1310_hardclock(void *); + +#define timer0_read_4(sc, reg) \ + bus_space_read_4(sc->lt_bst0, sc->lt_bsh0, reg) +#define timer0_write_4(sc, reg, val) \ + bus_space_write_4(sc->lt_bst0, sc->lt_bsh0, reg, val) +#define timer0_clear(sc) \ + do { \ + timer0_write_4(sc, RT_TIMER_LOAD, 0); \ + timer0_write_4(sc, RT_TIMER_VALUE, 0); \ + } while(0) + +#define timer1_read_4(sc, reg) \ + bus_space_read_4(sc->lt_bst1, sc->lt_bsh1, reg) +#define timer1_write_4(sc, reg, val) \ + bus_space_write_4(sc->lt_bst1, sc->lt_bsh1, reg, val) +#define timer1_clear(sc) \ + do { \ + timer1_write_4(sc, RT_TIMER_LOAD, 0); \ + timer1_write_4(sc, RT_TIMER_VALUE, 0); \ + } while(0) + +#define timer2_read_4(sc, reg) \ + bus_space_read_4(sc->lt_bst1, sc->lt_bsh2, reg) +#define timer2_write_4(sc, reg, val) \ + bus_space_write_4(sc->lt_bst2, sc->lt_bsh2, reg, val) +#define timer3_write_4(sc, reg, val) \ + bus_space_write_4(sc->lt_bst3, sc->lt_bsh3, reg, val) + + +static struct timecounter rt1310_timecounter = { + .tc_get_timecount = rt1310_get_timecount, + .tc_name = "RT1310ATimer1", + .tc_frequency = 0, /* will be filled later */ + .tc_counter_mask = ~0u, + .tc_quality = 1000, +}; + +static int +rt1310_timer_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "rt,timer")) + return (ENXIO); + + device_set_desc(dev, "RT1310 timer"); + return (BUS_PROBE_DEFAULT); +} + +static int +rt1310_timer_attach(device_t dev) +{ + void *intrcookie; + struct rt1310_timer_softc *sc = device_get_softc(dev); + phandle_t node; + uint32_t freq; + + if (timer_softc) + return (ENXIO); + + timer_softc = sc; + + if (bus_alloc_resources(dev, rt1310_timer_spec, sc->lt_res)) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->lt_bst0 = rman_get_bustag(sc->lt_res[0]); + sc->lt_bsh0 = rman_get_bushandle(sc->lt_res[0]); + sc->lt_bst1 = rman_get_bustag(sc->lt_res[1]); + sc->lt_bsh1 = rman_get_bushandle(sc->lt_res[1]); + sc->lt_bst2 = rman_get_bustag(sc->lt_res[2]); + sc->lt_bsh2 = rman_get_bushandle(sc->lt_res[2]); + sc->lt_bst3 = rman_get_bustag(sc->lt_res[3]); + sc->lt_bsh3 = rman_get_bushandle(sc->lt_res[3]); + + /* Timer2 interrupt */ + if (bus_setup_intr(dev, sc->lt_res[6], INTR_TYPE_CLK, + rt1310_hardclock, NULL, sc, &intrcookie)) { + device_printf(dev, "could not setup interrupt handler\n"); + bus_release_resources(dev, rt1310_timer_spec, sc->lt_res); + return (ENXIO); + } + + /* Enable timer clock */ +/* + rt1310_pwr_write(dev, LPC_CLKPWR_TIMCLK_CTRL1, + LPC_CLKPWR_TIMCLK_CTRL1_TIMER0 | + LPC_CLKPWR_TIMCLK_CTRL1_TIMER1); +*/ + + /* Get PERIPH_CLK encoded in parent bus 'bus-frequency' property */ + + node = ofw_bus_get_node(dev); + if (OF_getprop(OF_parent(node), "bus-frequency", &freq, + sizeof(pcell_t)) <= 0) { + bus_release_resources(dev, rt1310_timer_spec, sc->lt_res); + bus_teardown_intr(dev, sc->lt_res[2], intrcookie); + device_printf(dev, "could not obtain base clock frequency\n"); + return (ENXIO); + } + + freq = fdt32_to_cpu(freq); + + /* Set desired frequency in event timer and timecounter */ + sc->lt_et.et_frequency = (uint64_t)freq; + rt1310_timecounter.tc_frequency = (uint64_t)freq; + + sc->lt_et.et_name = "RT1310ATimer2"; + sc->lt_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT; + sc->lt_et.et_quality = 1000; + sc->lt_et.et_min_period = (0x00000002LLU << 32) / sc->lt_et.et_frequency; + sc->lt_et.et_max_period = (0xfffffffeLLU << 32) / sc->lt_et.et_frequency; + sc->lt_et.et_start = rt1310_timer_start; + sc->lt_et.et_stop = rt1310_timer_stop; + sc->lt_et.et_priv = sc; + + et_register(&sc->lt_et); + tc_init(&rt1310_timecounter); + + /* Reset and enable timecounter */ + + timer0_write_4(sc, RT_TIMER_CONTROL, 0); + timer1_write_4(sc, RT_TIMER_CONTROL, 0); + timer2_write_4(sc, RT_TIMER_CONTROL, 0); + timer3_write_4(sc, RT_TIMER_CONTROL, 0); + + timer1_write_4(sc, RT_TIMER_LOAD, ~0); + timer1_write_4(sc, RT_TIMER_VALUE, ~0); + timer1_write_4(sc, RT_TIMER_CONTROL, + RT_TIMER_CTRL_ENABLE | RT_TIMER_CTRL_PERIODCAL); + + /* DELAY() now can work properly */ + rt1310_timer_initialized = 1; + + return (0); +} + +static int +rt1310_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) +{ + struct rt1310_timer_softc *sc = (struct rt1310_timer_softc *)et->et_priv; + uint32_t ticks; + + if (period == 0) { + sc->lt_oneshot = 1; + sc->lt_period = 0; + } else { + sc->lt_oneshot = 0; + sc->lt_period = ((uint32_t)et->et_frequency * period) >> 32; + } + + if (first == 0) + ticks = sc->lt_period; + else + ticks = ((uint32_t)et->et_frequency * first) >> 32; + + /* Reset timer */ + timer2_write_4(sc, RT_TIMER_CONTROL, 0); + + /* Start timer */ + timer2_write_4(sc, RT_TIMER_LOAD, ticks); + timer2_write_4(sc, RT_TIMER_VALUE, ticks); + timer2_write_4(sc, RT_TIMER_CONTROL, + RT_TIMER_CTRL_ENABLE | RT_TIMER_CTRL_INTCTL); + + return (0); +} + +static int +rt1310_timer_stop(struct eventtimer *et) +{ + struct rt1310_timer_softc *sc = (struct rt1310_timer_softc *)et->et_priv; + + timer2_write_4(sc, RT_TIMER_CONTROL, 0); + + return (0); +} + +static device_method_t rt1310_timer_methods[] = { + DEVMETHOD(device_probe, rt1310_timer_probe), + DEVMETHOD(device_attach, rt1310_timer_attach), + { 0, 0 } +}; + +static driver_t rt1310_timer_driver = { + "timer", + rt1310_timer_methods, + sizeof(struct rt1310_timer_softc), +}; + +static devclass_t rt1310_timer_devclass; + +EARLY_DRIVER_MODULE(timer, simplebus, rt1310_timer_driver, rt1310_timer_devclass, 0, 0, BUS_PASS_TIMER); + +static int +rt1310_hardclock(void *arg) +{ + struct rt1310_timer_softc *sc = (struct rt1310_timer_softc *)arg; + + /* Reset pending interrupt */ + timer2_write_4(sc, RT_TIMER_CONTROL, + timer2_read_4(sc, RT_TIMER_CONTROL) | 0x08); + timer2_write_4(sc, RT_TIMER_CONTROL, + timer2_read_4(sc, RT_TIMER_CONTROL) & 0x1fb); + + /* Start timer again */ + if (!sc->lt_oneshot) { + timer2_write_4(sc, RT_TIMER_LOAD, sc->lt_period); + timer2_write_4(sc, RT_TIMER_VALUE, sc->lt_period); + timer2_write_4(sc, RT_TIMER_CONTROL, + RT_TIMER_CTRL_ENABLE | RT_TIMER_CTRL_INTCTL); + } + + if (sc->lt_et.et_active) + sc->lt_et.et_event_cb(&sc->lt_et, sc->lt_et.et_arg); + + return (FILTER_HANDLED); +} + +static unsigned +rt1310_get_timecount(struct timecounter *tc) +{ + return ~timer1_read_4(timer_softc, RT_TIMER_VALUE); +} + +void +DELAY(int usec) +{ + uint32_t counter; + uint32_t first, last; + int val = (rt1310_timecounter.tc_frequency / 1000000 + 1) * usec; + + /* Timer is not initialized yet */ + if (!rt1310_timer_initialized) { + for (; usec > 0; usec--) + for (counter = 100; counter > 0; counter--) + ; + return; + } + + first = rt1310_get_timecount(&rt1310_timecounter); + while (val > 0) { + last = rt1310_get_timecount(&rt1310_timecounter); + if (last < first) { + /* Timer rolled over */ + last = first; + } + + val -= (last - first); + first = last; + } +} Property changes on: head/sys/arm/ralink/rt1310_timer.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ralink/rt1310reg.h =================================================================== --- head/sys/arm/ralink/rt1310reg.h (nonexistent) +++ head/sys/arm/ralink/rt1310reg.h (revision 317872) @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2011 Jakub Wojciech Klama + * Copyright (c) 2015 Hiroki Mori + * 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 _ARM_RALINK_RT1310REG_H +#define _ARM_RALINK_RT1310REG_H + +/* + * Interrupt controller + */ + +#define RT_INTC_SCR0 0x00 +#define RT_INTC_SVR0 0x80 +#define RT_INTC_ISR 0x104 +#define RT_INTC_IPR 0x108 +#define RT_INTC_IMR 0x10c +#define RT_INTC_IECR 0x114 +#define RT_INTC_ICCR 0x118 + +#define RT_INTC_TRIG_LOW_LVL (0) +#define RT_INTC_TRIG_HIGH_LVL (1) +#define RT_INTC_TRIG_NEG_EDGE (2) +#define RT_INTC_TRIG_POS_EDGE (3) + +#define RT_INTC_TRIG_SHIF 6 + +/* + * Timer 0|1|2|3. + */ + +#define RT_TIMER_LOAD 0x00 +#define RT_TIMER_VALUE 0x04 +#define RT_TIMER_CONTROL 0x08 + +#define RT_TIMER_CTRL_INTCTL (1 << 1) +#define RT_TIMER_CTRL_INTCLR (1 << 2) +#define RT_TIMER_CTRL_INTMASK (1 << 3) +#define RT_TIMER_CTRL_DIV16 (3 << 4) +#define RT_TIMER_CTRL_DIV256 (7 << 4) +#define RT_TIMER_CTRL_PERIODCAL (1 << 7) +#define RT_TIMER_CTRL_ENABLE (1 << 8) + +#define RT_TIMER_INTERVAL (5000*150) + +/* + * GPIO + */ + +#define RT_GPIO_PORTA (0) +#define RT_GPIO_PORTB (1) + +#define RT_GPIO_OFF_PADR (0x0) +#define RT_GPIO_OFF_PADIR (0x4) +#define RT_GPIO_OFF_PBDR (0x8) +#define RT_GPIO_OFF_PBDIR (0xC) + +#endif /* _ARM_RALINK_RT1310REG_H */ Property changes on: head/sys/arm/ralink/rt1310reg.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ralink/rt1310var.h =================================================================== --- head/sys/arm/ralink/rt1310var.h (nonexistent) +++ head/sys/arm/ralink/rt1310var.h (revision 317872) @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2011 Jakub Wojciech Klama + * 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 _ARM_RT_RTVAR_H +#define _ARM_RT_RTVAR_H + +#include +#include +#include + +/* Clocking and power control */ +uint32_t lpc_pwr_read(device_t, int); +void lpc_pwr_write(device_t, int, uint32_t); + +/* GPIO */ +void rt1310_gpio_init(void); +int rt1310_gpio_set_flags(device_t, int, int); +int rt1310_gpio_set_state(device_t, int, int); +int rt1310_gpio_get_state(device_t, int, int *); + +/* DMA */ +struct lpc_dmac_channel_config +{ + int ldc_fcntl; + int ldc_src_periph; + int ldc_src_width; + int ldc_src_incr; + int ldc_src_burst; + int ldc_dst_periph; + int ldc_dst_width; + int ldc_dst_incr; + int ldc_dst_burst; + void (*ldc_success_handler)(void *); + void (*ldc_error_handler)(void *); + void * ldc_handler_arg; +}; + +int lpc_dmac_config_channel(device_t, int, struct lpc_dmac_channel_config *); +int lpc_dmac_setup_transfer(device_t, int, bus_addr_t, bus_addr_t, bus_size_t, int); +int lpc_dmac_enable_channel(device_t, int); +int lpc_dmac_disable_channel(device_t, int); +int lpc_dmac_start_burst(device_t, int); + +extern uint32_t rt1310_master_clock; + +#endif /* _ARM_RT_RTVAR_H */ Property changes on: head/sys/arm/ralink/rt1310var.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/boot/fdt/dts/arm/rt1310a.dtsi =================================================================== --- head/sys/boot/fdt/dts/arm/rt1310a.dtsi (nonexistent) +++ head/sys/boot/fdt/dts/arm/rt1310a.dtsi (revision 317872) @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2011 Jakub Klama + * Copyright (c) 2015 Hiroki Mori + * + * 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. + * + * Ralink RT1310A Device Tree Source. + * + * $FreeBSD$ + */ + +/ { + compatible = "ralink,rt1310a-soc"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + serial0 = &serial0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "ARM,926EJ-S"; + reg = <0x0>; + d-cache-line-size = <32>; // 32 bytes + i-cache-line-size = <32>; // 32 bytes + d-cache-size = <0x4000>; // L1, 16K + i-cache-size = <0x4000>; // L1, 16K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x40000000 0x1000000>; // 16M at 0x40000000 + }; + + localbus@1f000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x0 0x1f000000 0x400000>; + }; + + ahb@19C00000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x0 0x19C00000 0xE0000>; + bus-frequency = <13000000>; + + PIC: pic@40000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + reg = <0x40000 0x20000>; + compatible = "rt,pic"; + }; + + fvmdio@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fv,mdio"; + reg = <0x80000 0x20000>; + }; + + enet0:fv_mac0@80000 { + compatible = "fv,ethernet"; + reg = <0x80000 0x20000>; + interrupts = <7>; + interrupt-parent = <&PIC>; + + }; + + enet1:fv_mac1@A0000 { + compatible = "fv,ethernet"; + reg = <0xA0000 0x20000>; + interrupts = <8>; + interrupt-parent = <&PIC>; + }; + + }; + + apb@1E800000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x0 0x1E800000 0x800000>; + bus-frequency = <75000000>; + + timer@000000 { + compatible = "rt,timer"; + reg = <0x0 0x10 + 0x10 0x10 + 0x20 0x10 + 0x30 0x10>; + interrupts = <3 4 5>; + interrupt-parent = <&PIC>; + }; + + rtc@20000 { + compatible = "rt,rtc"; + interrupts = <6>; + reg = <0x20000 0x20000>; + }; + + serial0: serial@40000 { + compatible = "ns16550"; + reg = <0x40000 0x20000>; + interrupts = <1>; + reg-shift = <2>; + clock-frequency = <6758400>; + current-speed = <38400>; + interrupt-parent = <&PIC>; + }; + + gpio0: gpio@A0000 { + compatible = "ralink,rt1310-gpio"; + gpio-controller; + #gpio-cells = <2>; + interrupts = <8>; + reg = <0xA0000 0x20000>; + }; + }; + + +/* + chosen { + stdin = "serial0"; + stdout = "serial0"; + }; +*/ +}; + Property changes on: head/sys/boot/fdt/dts/arm/rt1310a.dtsi ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/boot/fdt/dts/arm/wzr2-g300n.dts =================================================================== --- head/sys/boot/fdt/dts/arm/wzr2-g300n.dts (nonexistent) +++ head/sys/boot/fdt/dts/arm/wzr2-g300n.dts (revision 317872) @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015 Hiroki Mori + * + * 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. + * + * Buffalo WZR2-G300N Device Tree Source. + * + * $FreeBSD$ + */ + +/dts-v1/; + +#include "rt1310a.dtsi" + +/ { + compatible = "WZR2-G300N", "ralink,rt1310a-soc"; + model = "WZR2-G300N"; + + flash@1f000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x1f000000 0x400000>; // 4M at 0x1f000000 + + partition@0 { + reg = <0x00000000 0x0000e000>; + label = "uboot"; + }; + partition@1 { + reg = <0x0000e000 0x00002000>; + label = "uboot_env"; + }; + partition@2 { + reg = <0x00010000 0x000f0000>; + label = "kernel"; + }; + partition@3 { + reg = <0x00100000 0x002d0000>; + label = "rootfs"; + }; + partition@4 { + reg = <0x003d0000 0x00010000>; + label = "config"; + }; + partition@5 { + reg = <0x00010000 0x003c0000>; + label = "upgrade"; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + status { + label = "status"; + gpios = <&gpio0 4 0>; + }; + }; + + ip17x@0 { + compatible = "icplus,ip17x"; + mii-poll = <0>; + }; + +}; + +&enet0 { + local-mac-address = [ 00 1a f1 01 1f 23 ]; +}; + +&enet1 { + local-mac-address = [ 00 1a f1 01 1f 24 ]; +}; Property changes on: head/sys/boot/fdt/dts/arm/wzr2-g300n.dts ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property