/* $NetBSD: bcm2835_obio.c,v 1.26 2015/11/21 07:41:29 mlelstv Exp $ */ /*- * Copyright (c) 2012, 2014 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Nick Hudson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: bcm2835_obio.c,v 1.26 2015/11/21 07:41:29 mlelstv Exp $"); #include "locators.h" #include "obio.h" #include "opt_bcm283x.h" #include #include #include #include #include #include #include #include #include #include struct obio_softc { device_t sc_dev; bus_dma_tag_t sc_dmat; struct arm32_dma_range sc_dmarange[1]; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; bus_addr_t sc_base; bus_size_t sc_size; }; static bool obio_attached; /* prototypes */ static int obio_match(device_t, cfdata_t, void *); static void obio_attach(device_t, device_t, void *); static int obio_print(void *, const char *); /* attach structures */ CFATTACH_DECL_NEW(obio, sizeof(struct obio_softc), obio_match, obio_attach, NULL, NULL); /* * List of port-specific devices to attach to the AMBA AXI bus. */ static const struct ambadev_locators bcm2835_ambadev_locs[] = { { /* Interrupt controller */ .ad_name = "icu", .ad_addr = BCM2835_ARMICU_BASE, .ad_size = BCM2835_ARMICU_SIZE, .ad_intr = -1, }, #if defined(BCM2836) { /* GTMR */ .ad_name = "armgtmr", .ad_intr = BCM2836_INT_CNTVIRQ_CPUN(0), }, #endif { /* Mailbox */ .ad_name = "bcmmbox", .ad_addr = BCM2835_ARMMBOX_BASE, .ad_size = BCM2835_ARMMBOX_SIZE, .ad_intr = BCM2835_INT_ARMMAILBOX }, #if !defined(BCM2836) { /* System Timer */ .ad_name = "bcmtmr", .ad_addr = BCM2835_STIMER_BASE, .ad_size = BCM2835_STIMER_SIZE, .ad_intr = BCM2835_INT_TIMER3, }, #endif { /* VCHIQ */ .ad_name = "bcmvchiq", .ad_addr = BCM2835_VCHIQ_BASE, .ad_size = BCM2835_VCHIQ_SIZE, .ad_intr = BCM2835_INT_ARMDOORBELL0, }, { /* Power Management, Reset controller and Watchdog registers */ .ad_name = "bcmpm", .ad_addr = BCM2835_PM_BASE, .ad_size = BCM2835_PM_SIZE, .ad_intr = -1, }, { /* DMA Controller */ .ad_name = "bcmdmac", .ad_addr = BCM2835_DMA0_BASE, .ad_size = BCM2835_DMA0_SIZE, .ad_intr = -1, }, { /* Random number generator */ .ad_name = "bcmrng", .ad_addr = BCM2835_RNG_BASE, .ad_size = BCM2835_RNG_SIZE, .ad_intr = -1, }, { /* Uart 0 */ .ad_name = "plcom", .ad_addr = BCM2835_UART0_BASE, .ad_size = BCM2835_UART0_SIZE, .ad_intr = BCM2835_INT_UART0, }, { /* Framebuffer */ .ad_name = "fb", .ad_addr = 0, .ad_size = 0, .ad_intr = -1, }, { /* eMMC interface */ .ad_name = "emmc", .ad_addr = BCM2835_EMMC_BASE, .ad_size = BCM2835_EMMC_SIZE, .ad_intr = BCM2835_INT_EMMC, }, { /* DesignWare_OTG USB controller */ .ad_name = "dwctwo", .ad_addr = BCM2835_USB_BASE, .ad_size = BCM2835_USB_SIZE, .ad_intr = BCM2835_INT_USB, }, { .ad_name = "bcmspi", .ad_addr = BCM2835_SPI0_BASE, .ad_size = BCM2835_SPI0_SIZE, .ad_intr = BCM2835_INT_SPI0, }, { .ad_name = "bcmbsc", .ad_addr = BCM2835_BSC0_BASE, .ad_size = BCM2835_BSC_SIZE, .ad_intr = BCM2835_INT_BSC, }, { .ad_name = "bcmbsc", .ad_addr = BCM2835_BSC1_BASE, .ad_size = BCM2835_BSC_SIZE, .ad_intr = BCM2835_INT_BSC, }, { /* gpio */ .ad_name = "bcmgpio", .ad_addr = BCM2835_GPIO_BASE, .ad_size = BCM2835_GPIO_SIZE, .ad_intr = -1, }, { /* gpio */ .ad_name = "bcmgpio", .ad_addr = BCM2835_GPIO_BASE, .ad_size = BCM2835_GPIO_SIZE, .ad_intr = -1, }, { /* Clock Manager */ .ad_name = "bcmcm", .ad_addr = BCM2835_CM_BASE, .ad_size = BCM2835_CM_SIZE, .ad_intr = -1, }, { /* PWM Controller */ .ad_name = "bcmpwm", .ad_addr = BCM2835_PWM_BASE, .ad_size = BCM2835_PWM_SIZE, .ad_intr = -1, }, { /* Terminator */ .ad_name = NULL, } }; static int obio_match(device_t parent, cfdata_t match, void *aux) { return 1; } bus_space_tag_t al_iot = &bcm2835_bs_tag; bus_space_handle_t al_ioh; static void obio_attach(device_t parent, device_t self, void *aux) { struct obio_softc *sc = device_private(self); const struct ambadev_locators *ad = bcm2835_ambadev_locs; struct amba_attach_args aaa; int locs[OBIOCF_NLOCS]; if (obio_attached) return; obio_attached = true; sc->sc_dev = self; sc->sc_dmat = &bcm2835_bus_dma_tag; sc->sc_dmarange[0].dr_sysbase = 0; #if defined(BCM2836) sc->sc_dmarange[0].dr_busbase = BCM2835_BUSADDR_CACHE_DIRECT; #else sc->sc_dmarange[0].dr_busbase = BCM2835_BUSADDR_CACHE_COHERENT; #endif sc->sc_dmarange[0].dr_len = physmem * PAGE_SIZE; bcm2835_bus_dma_tag._ranges = sc->sc_dmarange; bcm2835_bus_dma_tag._nranges = __arraycount(sc->sc_dmarange); aprint_normal("\n"); /* Set up the attach args. */ aaa.aaa_iot = &bcm2835_bs_tag; aaa.aaa_dmat = sc->sc_dmat; #if defined(BCM2836) if (bus_space_map(al_iot, BCM2836_ARM_LOCAL_BASE, BCM2836_ARM_LOCAL_SIZE, 0, &al_ioh)) { aprint_error(": unable to map local space\n"); return; } bus_space_write_4(al_iot, al_ioh, BCM2836_LOCAL_CONTROL, 0); bus_space_write_4(al_iot, al_ioh, BCM2836_LOCAL_PRESCALER, 0x80000000); #endif for (; ad->ad_name != NULL; ad++) { aprint_debug("dev=%s[%u], addr=%lx:+%lx\n", ad->ad_name, ad->ad_instance, ad->ad_addr, ad->ad_size); if (strcmp(ad->ad_name, "armgtmr") == 0) { struct mpcore_attach_args mpcaa = { .mpcaa_name = "armgtmr", .mpcaa_irq = ad->ad_intr, }; config_found(self, &mpcaa, NULL); continue; } aaa.aaa_name = ad->ad_name; aaa.aaa_addr = ad->ad_addr; aaa.aaa_size = ad->ad_size; aaa.aaa_intr = ad->ad_intr; /* ad->ad_instance; */ locs[OBIOCF_ADDR] = ad->ad_addr; locs[OBIOCF_SIZE] = ad->ad_size; locs[OBIOCF_INTR] = ad->ad_intr; config_found_sm_loc(self, "obio", locs, &aaa, obio_print, config_stdsubmatch); } return; } static int obio_print(void *aux, const char *name) { struct amba_attach_args *aaa = aux; if (name) aprint_normal("%s at %s", aaa->aaa_name, name); else { #if 0 if (aaa->aaa_unit != OBIOCF_UNIT_DEFAULT) aprint_normal(" unit %d", aaa->aaa_unit); if (aaa->aaa_addr != OBIOCF_ADDR_DEFAULT) { aprint_normal(" addr 0x%lx", aaa->aaa_addr); if (aaa->aaa_size > 0) aprint_normal("-0x%lx", aaa->aaa_addr + aaa->aaa_size - 1); } #endif if (aaa->aaa_intr != OBIOCF_INTR_DEFAULT) aprint_normal(" intr %d", aaa->aaa_intr); } return UNCONF; } #ifdef MULTIPROCESSOR void bcm2836_cpu_hatch(struct cpu_info *ci) { bcm2836mp_intr_init(ci); gtmr_init_cpu_clock(ci); } #endif