1155324Simp/*- 2155324Simp * Copyright (c) 2005 Olivier Houchard. All rights reserved. 3213496Scognet * Copyright (c) 2010 Greg Ansley. All rights reserved. 4155324Simp * 5155324Simp * Redistribution and use in source and binary forms, with or without 6155324Simp * modification, are permitted provided that the following conditions 7155324Simp * are met: 8155324Simp * 1. Redistributions of source code must retain the above copyright 9155324Simp * notice, this list of conditions and the following disclaimer. 10155324Simp * 2. Redistributions in binary form must reproduce the above copyright 11155324Simp * notice, this list of conditions and the following disclaimer in the 12155324Simp * documentation and/or other materials provided with the distribution. 13155324Simp * 14185265Simp * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15185265Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16185265Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17185265Simp * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18185265Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19185265Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20185265Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21185265Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22185265Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23185265Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24185265Simp * SUCH DAMAGE. 25155324Simp */ 26155324Simp 27262925Simp#include "opt_platform.h" 28262925Simp 29155324Simp#include <sys/cdefs.h> 30155324Simp__FBSDID("$FreeBSD: releng/11.0/sys/arm/at91/at91.c 298627 2016-04-26 11:53:37Z br $"); 31155324Simp 32155324Simp#include <sys/param.h> 33155324Simp#include <sys/systm.h> 34155324Simp#include <sys/bus.h> 35155324Simp#include <sys/kernel.h> 36155324Simp#include <sys/malloc.h> 37155324Simp#include <sys/module.h> 38298627Sbr#include <sys/devmap.h> 39155324Simp 40155324Simp#include <vm/vm.h> 41155324Simp#include <vm/vm_kern.h> 42155324Simp#include <vm/pmap.h> 43155324Simp#include <vm/vm_page.h> 44155324Simp#include <vm/vm_extern.h> 45155324Simp 46271398Sandrew#include <machine/armreg.h> 47155324Simp#define _ARM32_BUS_DMA_PRIVATE 48155324Simp#include <machine/bus.h> 49155324Simp#include <machine/intr.h> 50155324Simp 51155324Simp#include <arm/at91/at91var.h> 52213496Scognet#include <arm/at91/at91_pmcvar.h> 53213496Scognet#include <arm/at91/at91_aicreg.h> 54155324Simp 55213496Scognetuint32_t at91_master_clock; 56187599Simp 57213496Scognetstruct arm32_dma_range * 58213496Scognetbus_dma_get_range(void) 59213496Scognet{ 60213496Scognet 61213496Scognet return (NULL); 62213496Scognet} 63213496Scognet 64213496Scognetint 65213496Scognetbus_dma_get_range_nb(void) 66213496Scognet{ 67213496Scognet return (0); 68213496Scognet} 69213496Scognet 70262925Simp#ifndef FDT 71262925Simp 72262925Simpstatic struct at91_softc *at91_softc; 73262925Simp 74262925Simpstatic void at91_eoi(void *); 75262925Simp 76155324Simpstatic int 77155324Simpat91_probe(device_t dev) 78155324Simp{ 79213496Scognet 80260093Simp device_set_desc(dev, soc_info.name); 81257370Snwhitehorn return (BUS_PROBE_NOWILDCARD); 82155324Simp} 83155324Simp 84155324Simpstatic void 85155324Simpat91_identify(driver_t *drv, device_t parent) 86155324Simp{ 87155324Simp 88155324Simp BUS_ADD_CHILD(parent, 0, "atmelarm", 0); 89155324Simp} 90155324Simp 91238390Simpstatic void 92238390Simpat91_cpu_add_builtin_children(device_t dev, const struct cpu_devs *walker) 93238390Simp{ 94238390Simp int i; 95238390Simp 96269960Simp for (i = 0; walker->name; i++, walker++) { 97238390Simp at91_add_child(dev, i, walker->name, walker->unit, 98238390Simp walker->mem_base, walker->mem_len, walker->irq0, 99238390Simp walker->irq1, walker->irq2); 100238390Simp } 101238390Simp} 102238390Simp 103155324Simpstatic int 104155324Simpat91_attach(device_t dev) 105155324Simp{ 106155324Simp struct at91_softc *sc = device_get_softc(dev); 107155324Simp 108257343Snwhitehorn arm_post_filter = at91_eoi; 109257343Snwhitehorn 110155324Simp at91_softc = sc; 111294133Simp sc->sc_st = arm_base_bs_tag; 112213496Scognet sc->sc_sh = AT91_BASE; 113238389Simp sc->sc_aic_sh = AT91_BASE + AT91_SYS_BASE; 114155324Simp sc->dev = dev; 115213496Scognet 116155324Simp sc->sc_irq_rman.rm_type = RMAN_ARRAY; 117164432Simp sc->sc_irq_rman.rm_descr = "AT91 IRQs"; 118155324Simp if (rman_init(&sc->sc_irq_rman) != 0 || 119155324Simp rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0) 120155324Simp panic("at91_attach: failed to set up IRQ rman"); 121213496Scognet 122213496Scognet sc->sc_mem_rman.rm_type = RMAN_ARRAY; 123213496Scognet sc->sc_mem_rman.rm_descr = "AT91 Memory"; 124213496Scognet if (rman_init(&sc->sc_mem_rman) != 0) 125155324Simp panic("at91_attach: failed to set up memory rman"); 126261322Simp /* 127261322Simp * Manage the physical space, defined as being everything that isn't 128261322Simp * DRAM. 129261322Simp */ 130261322Simp if (rman_manage_region(&sc->sc_mem_rman, 0, PHYSADDR - 1) != 0) 131261322Simp panic("at91_attach: failed to set up memory rman"); 132261322Simp if (rman_manage_region(&sc->sc_mem_rman, PHYSADDR + (256 << 20), 133261322Simp 0xfffffffful) != 0) 134261322Simp panic("at91_attach: failed to set up memory rman"); 135155324Simp 136238390Simp /* 137238390Simp * Add this device's children... 138238390Simp */ 139238390Simp at91_cpu_add_builtin_children(dev, soc_info.soc_data->soc_children); 140238398Simp soc_info.soc_data->soc_clock_init(); 141156828Simp 142155324Simp bus_generic_probe(dev); 143155324Simp bus_generic_attach(dev); 144271398Sandrew enable_interrupts(PSR_I | PSR_F); 145155324Simp return (0); 146155324Simp} 147155324Simp 148155324Simpstatic struct resource * 149155324Simpat91_alloc_resource(device_t dev, device_t child, int type, int *rid, 150294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 151155324Simp{ 152155324Simp struct at91_softc *sc = device_get_softc(dev); 153155324Simp struct resource_list_entry *rle; 154155324Simp struct at91_ivar *ivar = device_get_ivars(child); 155155324Simp struct resource_list *rl = &ivar->resources; 156261322Simp bus_space_handle_t bsh; 157155324Simp 158155324Simp if (device_get_parent(child) != dev) 159155324Simp return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 160155324Simp type, rid, start, end, count, flags)); 161155324Simp 162155324Simp rle = resource_list_find(rl, type, *rid); 163155324Simp if (rle == NULL) 164155324Simp return (NULL); 165155324Simp if (rle->res) 166155324Simp panic("Resource rid %d type %d already in use", *rid, type); 167295832Sjhibbits if (RMAN_IS_DEFAULT_RANGE(start, end)) { 168155324Simp start = rle->start; 169155324Simp count = ulmax(count, rle->count); 170155324Simp end = ulmax(rle->end, start + count - 1); 171155324Simp } 172155324Simp switch (type) 173155324Simp { 174155324Simp case SYS_RES_IRQ: 175155324Simp rle->res = rman_reserve_resource(&sc->sc_irq_rman, 176155324Simp start, end, count, flags, child); 177155324Simp break; 178155324Simp case SYS_RES_MEMORY: 179182805Simp rle->res = rman_reserve_resource(&sc->sc_mem_rman, 180182805Simp start, end, count, flags, child); 181184309Sstas if (rle->res != NULL) { 182294133Simp bus_space_map(arm_base_bs_tag, start, 183261322Simp rman_get_size(rle->res), 0, &bsh); 184294133Simp rman_set_bustag(rle->res, arm_base_bs_tag); 185261322Simp rman_set_bushandle(rle->res, bsh); 186184309Sstas } 187155324Simp break; 188155324Simp } 189155324Simp if (rle->res) { 190155324Simp rle->start = rman_get_start(rle->res); 191155324Simp rle->end = rman_get_end(rle->res); 192155324Simp rle->count = count; 193157891Simp rman_set_rid(rle->res, *rid); 194155324Simp } 195155324Simp return (rle->res); 196155324Simp} 197155324Simp 198155324Simpstatic struct resource_list * 199155324Simpat91_get_resource_list(device_t dev, device_t child) 200155324Simp{ 201155324Simp struct at91_ivar *ivar; 202155324Simp 203155324Simp ivar = device_get_ivars(child); 204155324Simp return (&(ivar->resources)); 205155324Simp} 206155324Simp 207155324Simpstatic int 208155324Simpat91_release_resource(device_t dev, device_t child, int type, 209155324Simp int rid, struct resource *r) 210155324Simp{ 211155324Simp struct resource_list *rl; 212155324Simp struct resource_list_entry *rle; 213155324Simp 214155324Simp rl = at91_get_resource_list(dev, child); 215155324Simp if (rl == NULL) 216155324Simp return (EINVAL); 217155324Simp rle = resource_list_find(rl, type, rid); 218155324Simp if (rle == NULL) 219155324Simp return (EINVAL); 220155324Simp rman_release_resource(r); 221155324Simp rle->res = NULL; 222155324Simp return (0); 223155324Simp} 224155324Simp 225155324Simpstatic int 226155324Simpat91_setup_intr(device_t dev, device_t child, 227236989Simp struct resource *ires, int flags, driver_filter_t *filt, 228236989Simp driver_intr_t *intr, void *arg, void **cookiep) 229155324Simp{ 230226832Skevlo int error; 231161704Scognet 232238348Simp if (rman_get_start(ires) == AT91_IRQ_SYSTEM && filt == NULL) 233167261Spiso panic("All system interrupt ISRs must be FILTER"); 234226832Skevlo error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, 235226832Skevlo filt, intr, arg, cookiep); 236226832Skevlo if (error) 237226832Skevlo return (error); 238226832Skevlo 239155324Simp return (0); 240155324Simp} 241155324Simp 242155324Simpstatic int 243155324Simpat91_teardown_intr(device_t dev, device_t child, struct resource *res, 244155324Simp void *cookie) 245155324Simp{ 246155324Simp struct at91_softc *sc = device_get_softc(dev); 247155324Simp 248236989Simp bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 249155324Simp 1 << rman_get_start(res)); 250155324Simp return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); 251155324Simp} 252155324Simp 253155324Simpstatic int 254155324Simpat91_activate_resource(device_t bus, device_t child, int type, int rid, 255155324Simp struct resource *r) 256155324Simp{ 257155324Simp#if 0 258294883Sjhibbits rman_res_t p; 259155324Simp int error; 260155324Simp 261155324Simp if (type == SYS_RES_MEMORY) { 262155324Simp error = bus_space_map(rman_get_bustag(r), 263155324Simp rman_get_bushandle(r), rman_get_size(r), 0, &p); 264236989Simp if (error) 265155324Simp return (error); 266155324Simp rman_set_bushandle(r, p); 267155324Simp } 268155324Simp#endif 269155324Simp return (rman_activate_resource(r)); 270155324Simp} 271155324Simp 272155324Simpstatic int 273155324Simpat91_print_child(device_t dev, device_t child) 274155324Simp{ 275155324Simp struct at91_ivar *ivars; 276155324Simp struct resource_list *rl; 277155324Simp int retval = 0; 278155324Simp 279155324Simp ivars = device_get_ivars(child); 280155324Simp rl = &ivars->resources; 281155324Simp 282155324Simp retval += bus_print_child_header(dev, child); 283155324Simp 284297199Sjhibbits retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx"); 285297199Sjhibbits retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 286297199Sjhibbits retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); 287155324Simp if (device_get_flags(dev)) 288155324Simp retval += printf(" flags %#x", device_get_flags(dev)); 289155324Simp 290155324Simp retval += bus_print_child_footer(dev, child); 291155324Simp 292155324Simp return (retval); 293155324Simp} 294155324Simp 295178366Scognetstatic void 296178366Scognetat91_eoi(void *unused) 297178366Scognet{ 298213496Scognet bus_space_write_4(at91_softc->sc_st, at91_softc->sc_aic_sh, 299178366Scognet IC_EOICR, 0); 300178366Scognet} 301178366Scognet 302238334Simpvoid 303238334Simpat91_add_child(device_t dev, int prio, const char *name, int unit, 304238334Simp bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) 305238334Simp{ 306238334Simp device_t kid; 307238334Simp struct at91_ivar *ivar; 308238334Simp 309238334Simp kid = device_add_child_ordered(dev, prio, name, unit); 310238334Simp if (kid == NULL) { 311238334Simp printf("Can't add child %s%d ordered\n", name, unit); 312238334Simp return; 313238334Simp } 314238334Simp ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 315238334Simp if (ivar == NULL) { 316238334Simp device_delete_child(dev, kid); 317238334Simp printf("Can't add alloc ivar\n"); 318238334Simp return; 319238334Simp } 320238334Simp device_set_ivars(kid, ivar); 321238334Simp resource_list_init(&ivar->resources); 322238334Simp if (irq0 != -1) { 323238334Simp bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); 324238334Simp if (irq0 != AT91_IRQ_SYSTEM) 325238334Simp at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0); 326238334Simp } 327238334Simp if (irq1 != 0) 328238334Simp bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); 329238334Simp if (irq2 != 0) 330238334Simp bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); 331261322Simp /* 332261322Simp * Special case for on-board devices. These have their address 333261322Simp * defined relative to AT91_PA_BASE in all the register files we 334261322Simp * have. We could change this, but that's a lot of effort which 335261322Simp * will be obsoleted when FDT arrives. 336261322Simp */ 337261322Simp if (addr != 0 && addr < 0x10000000 && addr >= 0x0f000000) 338261322Simp addr += AT91_PA_BASE; 339238334Simp if (addr != 0) 340238334Simp bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); 341238334Simp} 342238334Simp 343155324Simpstatic device_method_t at91_methods[] = { 344155324Simp DEVMETHOD(device_probe, at91_probe), 345155324Simp DEVMETHOD(device_attach, at91_attach), 346155324Simp DEVMETHOD(device_identify, at91_identify), 347155324Simp 348155324Simp DEVMETHOD(bus_alloc_resource, at91_alloc_resource), 349155324Simp DEVMETHOD(bus_setup_intr, at91_setup_intr), 350155324Simp DEVMETHOD(bus_teardown_intr, at91_teardown_intr), 351155324Simp DEVMETHOD(bus_activate_resource, at91_activate_resource), 352155324Simp DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 353155324Simp DEVMETHOD(bus_get_resource_list,at91_get_resource_list), 354155324Simp DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 355155324Simp DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 356155324Simp DEVMETHOD(bus_release_resource, at91_release_resource), 357155324Simp DEVMETHOD(bus_print_child, at91_print_child), 358155324Simp 359155324Simp {0, 0}, 360155324Simp}; 361155324Simp 362155324Simpstatic driver_t at91_driver = { 363155324Simp "atmelarm", 364155324Simp at91_methods, 365155324Simp sizeof(struct at91_softc), 366155324Simp}; 367213496Scognet 368155324Simpstatic devclass_t at91_devclass; 369155324Simp 370155324SimpDRIVER_MODULE(atmelarm, nexus, at91_driver, at91_devclass, 0, 0); 371262925Simp#endif 372