at91.c revision 331722
1/*- 2 * Copyright (c) 2005 Olivier Houchard. All rights reserved. 3 * Copyright (c) 2010 Greg Ansley. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include "opt_platform.h" 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: stable/11/sys/arm/at91/at91.c 331722 2018-03-29 02:50:57Z eadler $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/kernel.h> 36#include <sys/malloc.h> 37#include <sys/module.h> 38#include <sys/devmap.h> 39 40#include <vm/vm.h> 41#include <vm/vm_kern.h> 42#include <vm/pmap.h> 43#include <vm/vm_page.h> 44#include <vm/vm_extern.h> 45 46#include <machine/armreg.h> 47#define _ARM32_BUS_DMA_PRIVATE 48#include <machine/bus.h> 49#include <machine/intr.h> 50 51#include <arm/at91/at91var.h> 52#include <arm/at91/at91_pmcvar.h> 53#include <arm/at91/at91_aicreg.h> 54 55uint32_t at91_master_clock; 56 57struct arm32_dma_range * 58bus_dma_get_range(void) 59{ 60 61 return (NULL); 62} 63 64int 65bus_dma_get_range_nb(void) 66{ 67 return (0); 68} 69 70#ifndef FDT 71 72static struct at91_softc *at91_softc; 73 74static void at91_eoi(void *); 75 76static int 77at91_probe(device_t dev) 78{ 79 80 device_set_desc(dev, soc_info.name); 81 return (BUS_PROBE_NOWILDCARD); 82} 83 84static void 85at91_identify(driver_t *drv, device_t parent) 86{ 87 88 BUS_ADD_CHILD(parent, 0, "atmelarm", 0); 89} 90 91static void 92at91_cpu_add_builtin_children(device_t dev, const struct cpu_devs *walker) 93{ 94 int i; 95 96 for (i = 0; walker->name; i++, walker++) { 97 at91_add_child(dev, i, walker->name, walker->unit, 98 walker->mem_base, walker->mem_len, walker->irq0, 99 walker->irq1, walker->irq2); 100 } 101} 102 103static int 104at91_attach(device_t dev) 105{ 106 struct at91_softc *sc = device_get_softc(dev); 107 108 arm_post_filter = at91_eoi; 109 110 at91_softc = sc; 111 sc->sc_st = arm_base_bs_tag; 112 sc->sc_sh = AT91_BASE; 113 sc->sc_aic_sh = AT91_BASE + AT91_SYS_BASE; 114 sc->dev = dev; 115 116 sc->sc_irq_rman.rm_type = RMAN_ARRAY; 117 sc->sc_irq_rman.rm_descr = "AT91 IRQs"; 118 if (rman_init(&sc->sc_irq_rman) != 0 || 119 rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0) 120 panic("at91_attach: failed to set up IRQ rman"); 121 122 sc->sc_mem_rman.rm_type = RMAN_ARRAY; 123 sc->sc_mem_rman.rm_descr = "AT91 Memory"; 124 if (rman_init(&sc->sc_mem_rman) != 0) 125 panic("at91_attach: failed to set up memory rman"); 126 /* 127 * Manage the physical space, defined as being everything that isn't 128 * DRAM. 129 */ 130 if (rman_manage_region(&sc->sc_mem_rman, 0, PHYSADDR - 1) != 0) 131 panic("at91_attach: failed to set up memory rman"); 132 if (rman_manage_region(&sc->sc_mem_rman, PHYSADDR + (256 << 20), 133 0xfffffffful) != 0) 134 panic("at91_attach: failed to set up memory rman"); 135 136 /* 137 * Add this device's children... 138 */ 139 at91_cpu_add_builtin_children(dev, soc_info.soc_data->soc_children); 140 soc_info.soc_data->soc_clock_init(); 141 142 bus_generic_probe(dev); 143 bus_generic_attach(dev); 144 enable_interrupts(PSR_I | PSR_F); 145 return (0); 146} 147 148static struct resource * 149at91_alloc_resource(device_t dev, device_t child, int type, int *rid, 150 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 151{ 152 struct at91_softc *sc = device_get_softc(dev); 153 struct resource_list_entry *rle; 154 struct at91_ivar *ivar = device_get_ivars(child); 155 struct resource_list *rl = &ivar->resources; 156 bus_space_handle_t bsh; 157 158 if (device_get_parent(child) != dev) 159 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 160 type, rid, start, end, count, flags)); 161 162 rle = resource_list_find(rl, type, *rid); 163 if (rle == NULL) 164 return (NULL); 165 if (rle->res) 166 panic("Resource rid %d type %d already in use", *rid, type); 167 if (RMAN_IS_DEFAULT_RANGE(start, end)) { 168 start = rle->start; 169 count = ulmax(count, rle->count); 170 end = ulmax(rle->end, start + count - 1); 171 } 172 switch (type) 173 { 174 case SYS_RES_IRQ: 175 rle->res = rman_reserve_resource(&sc->sc_irq_rman, 176 start, end, count, flags, child); 177 break; 178 case SYS_RES_MEMORY: 179 rle->res = rman_reserve_resource(&sc->sc_mem_rman, 180 start, end, count, flags, child); 181 if (rle->res != NULL) { 182 bus_space_map(arm_base_bs_tag, start, 183 rman_get_size(rle->res), 0, &bsh); 184 rman_set_bustag(rle->res, arm_base_bs_tag); 185 rman_set_bushandle(rle->res, bsh); 186 } 187 break; 188 } 189 if (rle->res) { 190 rle->start = rman_get_start(rle->res); 191 rle->end = rman_get_end(rle->res); 192 rle->count = count; 193 rman_set_rid(rle->res, *rid); 194 } 195 return (rle->res); 196} 197 198static struct resource_list * 199at91_get_resource_list(device_t dev, device_t child) 200{ 201 struct at91_ivar *ivar; 202 203 ivar = device_get_ivars(child); 204 return (&(ivar->resources)); 205} 206 207static int 208at91_release_resource(device_t dev, device_t child, int type, 209 int rid, struct resource *r) 210{ 211 struct resource_list *rl; 212 struct resource_list_entry *rle; 213 214 rl = at91_get_resource_list(dev, child); 215 if (rl == NULL) 216 return (EINVAL); 217 rle = resource_list_find(rl, type, rid); 218 if (rle == NULL) 219 return (EINVAL); 220 rman_release_resource(r); 221 rle->res = NULL; 222 return (0); 223} 224 225static int 226at91_setup_intr(device_t dev, device_t child, 227 struct resource *ires, int flags, driver_filter_t *filt, 228 driver_intr_t *intr, void *arg, void **cookiep) 229{ 230 int error; 231 232 if (rman_get_start(ires) == AT91_IRQ_SYSTEM && filt == NULL) 233 panic("All system interrupt ISRs must be FILTER"); 234 error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, 235 filt, intr, arg, cookiep); 236 if (error) 237 return (error); 238 239 return (0); 240} 241 242static int 243at91_teardown_intr(device_t dev, device_t child, struct resource *res, 244 void *cookie) 245{ 246 struct at91_softc *sc = device_get_softc(dev); 247 248 bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 249 1 << rman_get_start(res)); 250 return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); 251} 252 253static int 254at91_activate_resource(device_t bus, device_t child, int type, int rid, 255 struct resource *r) 256{ 257#if 0 258 rman_res_t p; 259 int error; 260 261 if (type == SYS_RES_MEMORY) { 262 error = bus_space_map(rman_get_bustag(r), 263 rman_get_bushandle(r), rman_get_size(r), 0, &p); 264 if (error) 265 return (error); 266 rman_set_bushandle(r, p); 267 } 268#endif 269 return (rman_activate_resource(r)); 270} 271 272static int 273at91_print_child(device_t dev, device_t child) 274{ 275 struct at91_ivar *ivars; 276 struct resource_list *rl; 277 int retval = 0; 278 279 ivars = device_get_ivars(child); 280 rl = &ivars->resources; 281 282 retval += bus_print_child_header(dev, child); 283 284 retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx"); 285 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 286 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); 287 if (device_get_flags(dev)) 288 retval += printf(" flags %#x", device_get_flags(dev)); 289 290 retval += bus_print_child_footer(dev, child); 291 292 return (retval); 293} 294 295static void 296at91_eoi(void *unused) 297{ 298 bus_space_write_4(at91_softc->sc_st, at91_softc->sc_aic_sh, 299 IC_EOICR, 0); 300} 301 302void 303at91_add_child(device_t dev, int prio, const char *name, int unit, 304 bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) 305{ 306 device_t kid; 307 struct at91_ivar *ivar; 308 309 kid = device_add_child_ordered(dev, prio, name, unit); 310 if (kid == NULL) { 311 printf("Can't add child %s%d ordered\n", name, unit); 312 return; 313 } 314 ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 315 if (ivar == NULL) { 316 device_delete_child(dev, kid); 317 printf("Can't add alloc ivar\n"); 318 return; 319 } 320 device_set_ivars(kid, ivar); 321 resource_list_init(&ivar->resources); 322 if (irq0 != -1) { 323 bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); 324 if (irq0 != AT91_IRQ_SYSTEM) 325 at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0); 326 } 327 if (irq1 != 0) 328 bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); 329 if (irq2 != 0) 330 bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); 331 /* 332 * Special case for on-board devices. These have their address 333 * defined relative to AT91_PA_BASE in all the register files we 334 * have. We could change this, but that's a lot of effort which 335 * will be obsoleted when FDT arrives. 336 */ 337 if (addr != 0 && addr < 0x10000000 && addr >= 0x0f000000) 338 addr += AT91_PA_BASE; 339 if (addr != 0) 340 bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); 341} 342 343static device_method_t at91_methods[] = { 344 DEVMETHOD(device_probe, at91_probe), 345 DEVMETHOD(device_attach, at91_attach), 346 DEVMETHOD(device_identify, at91_identify), 347 348 DEVMETHOD(bus_alloc_resource, at91_alloc_resource), 349 DEVMETHOD(bus_setup_intr, at91_setup_intr), 350 DEVMETHOD(bus_teardown_intr, at91_teardown_intr), 351 DEVMETHOD(bus_activate_resource, at91_activate_resource), 352 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 353 DEVMETHOD(bus_get_resource_list,at91_get_resource_list), 354 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 355 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 356 DEVMETHOD(bus_release_resource, at91_release_resource), 357 DEVMETHOD(bus_print_child, at91_print_child), 358 359 {0, 0}, 360}; 361 362static driver_t at91_driver = { 363 "atmelarm", 364 at91_methods, 365 sizeof(struct at91_softc), 366}; 367 368static devclass_t at91_devclass; 369 370DRIVER_MODULE(atmelarm, nexus, at91_driver, at91_devclass, 0, 0); 371#endif 372