1179595Sbenno/*- 2179595Sbenno * Copyright (c) 2006 Benno Rice. All rights reserved. 3179595Sbenno * 4179595Sbenno * Redistribution and use in source and binary forms, with or without 5179595Sbenno * modification, are permitted provided that the following conditions 6179595Sbenno * are met: 7179595Sbenno * 1. Redistributions of source code must retain the above copyright 8179595Sbenno * notice, this list of conditions and the following disclaimer. 9179595Sbenno * 2. Redistributions in binary form must reproduce the above copyright 10179595Sbenno * notice, this list of conditions and the following disclaimer in the 11179595Sbenno * documentation and/or other materials provided with the distribution. 12179595Sbenno * 13179595Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14179595Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15179595Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16179595Sbenno * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17179595Sbenno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18179595Sbenno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19179595Sbenno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20179595Sbenno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21179595Sbenno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22179595Sbenno * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23179595Sbenno */ 24179595Sbenno 25179595Sbenno#include <sys/cdefs.h> 26179595Sbenno__FBSDID("$FreeBSD$"); 27179595Sbenno 28179595Sbenno#include <sys/param.h> 29179595Sbenno#include <sys/systm.h> 30179595Sbenno#include <sys/bus.h> 31179595Sbenno#include <sys/kernel.h> 32179595Sbenno#include <sys/module.h> 33179595Sbenno#include <sys/malloc.h> 34179595Sbenno#include <sys/rman.h> 35179595Sbenno#include <sys/timetc.h> 36179595Sbenno#include <machine/bus.h> 37179595Sbenno#include <machine/intr.h> 38179595Sbenno 39179595Sbenno#include <vm/vm.h> 40179595Sbenno#include <vm/pmap.h> 41179595Sbenno 42179595Sbenno#include <arm/xscale/pxa/pxavar.h> 43179595Sbenno#include <arm/xscale/pxa/pxareg.h> 44179595Sbenno 45227293Sedstatic MALLOC_DEFINE(M_PXASMI, "PXA SMI", 46227293Sed "Data for static memory interface devices."); 47179595Sbenno 48179595Sbennostruct pxa_smi_softc { 49179595Sbenno struct resource *ps_res[1]; 50179595Sbenno struct rman ps_mem; 51179595Sbenno bus_space_tag_t ps_bst; 52179595Sbenno bus_addr_t ps_base; 53179595Sbenno}; 54179595Sbenno 55179595Sbennostruct smi_ivars { 56179595Sbenno struct resource_list smid_resources; 57179595Sbenno bus_addr_t smid_mem; 58179595Sbenno}; 59179595Sbenno 60179595Sbennostatic struct resource_spec pxa_smi_spec[] = { 61179595Sbenno { SYS_RES_MEMORY, 0, RF_ACTIVE }, 62179595Sbenno { -1, 0 } 63179595Sbenno}; 64179595Sbenno 65179595Sbennostatic int pxa_smi_probe(device_t); 66179595Sbennostatic int pxa_smi_attach(device_t); 67179595Sbenno 68179595Sbennostatic int pxa_smi_print_child(device_t, device_t); 69179595Sbenno 70179595Sbennostatic int pxa_smi_read_ivar(device_t, device_t, int, uintptr_t *); 71179595Sbenno 72179595Sbennostatic struct resource * pxa_smi_alloc_resource(device_t, device_t, 73179595Sbenno int, int *, u_long, u_long, u_long, u_int); 74179595Sbennostatic int pxa_smi_release_resource(device_t, device_t, 75179595Sbenno int, int, struct resource *); 76179595Sbennostatic int pxa_smi_activate_resource(device_t, device_t, 77179595Sbenno int, int, struct resource *); 78179595Sbenno 79179595Sbennostatic void pxa_smi_add_device(device_t, const char *, int); 80179595Sbenno 81179595Sbennostatic int 82179595Sbennopxa_smi_probe(device_t dev) 83179595Sbenno{ 84179595Sbenno 85241885Seadler if (resource_disabled("smi", device_get_unit(dev))) 86241885Seadler return (ENXIO); 87241885Seadler 88179595Sbenno device_set_desc(dev, "Static Memory Interface"); 89179595Sbenno return (0); 90179595Sbenno} 91179595Sbenno 92179595Sbennostatic int 93179595Sbennopxa_smi_attach(device_t dev) 94179595Sbenno{ 95179595Sbenno int error, i, dunit; 96179595Sbenno const char *dname; 97179595Sbenno struct pxa_smi_softc *sc; 98179595Sbenno 99179595Sbenno sc = (struct pxa_smi_softc *)device_get_softc(dev); 100179595Sbenno 101179595Sbenno error = bus_alloc_resources(dev, pxa_smi_spec, sc->ps_res); 102179595Sbenno if (error) { 103179595Sbenno device_printf(dev, "could not allocate resources\n"); 104179595Sbenno return (ENXIO); 105179595Sbenno } 106179595Sbenno 107179595Sbenno sc->ps_mem.rm_type = RMAN_ARRAY; 108179595Sbenno sc->ps_mem.rm_descr = device_get_nameunit(dev); 109179595Sbenno if (rman_init(&sc->ps_mem) != 0) 110179595Sbenno panic("pxa_smi_attach: failed to init mem rman"); 111179595Sbenno if (rman_manage_region(&sc->ps_mem, 0, PXA2X0_CS_SIZE * 6) != 0) 112179595Sbenno panic("pxa_smi_attach: failed ot set up mem rman"); 113179595Sbenno 114179595Sbenno sc->ps_bst = base_tag; 115179595Sbenno sc->ps_base = rman_get_start(sc->ps_res[0]); 116179595Sbenno 117179595Sbenno i = 0; 118179595Sbenno while (resource_find_match(&i, &dname, &dunit, "at", 119179595Sbenno device_get_nameunit(dev)) == 0) { 120179595Sbenno pxa_smi_add_device(dev, dname, dunit); 121179595Sbenno } 122179595Sbenno 123179595Sbenno bus_generic_probe(dev); 124179595Sbenno bus_generic_attach(dev); 125179595Sbenno 126179595Sbenno return (0); 127179595Sbenno} 128179595Sbenno 129179595Sbennostatic int 130179595Sbennopxa_smi_print_child(device_t dev, device_t child) 131179595Sbenno{ 132179595Sbenno struct smi_ivars *smid; 133179595Sbenno int retval; 134179595Sbenno 135179595Sbenno smid = (struct smi_ivars *)device_get_ivars(child); 136179595Sbenno if (smid == NULL) { 137179595Sbenno device_printf(dev, "unknown device: %s\n", 138179595Sbenno device_get_nameunit(child)); 139179595Sbenno return (0); 140179595Sbenno } 141179595Sbenno 142179595Sbenno retval = 0; 143179595Sbenno 144179595Sbenno retval += bus_print_child_header(dev, child); 145179595Sbenno 146179595Sbenno retval += resource_list_print_type(&smid->smid_resources, "at mem", 147179595Sbenno SYS_RES_MEMORY, "%#lx"); 148179595Sbenno retval += resource_list_print_type(&smid->smid_resources, "irq", 149179595Sbenno SYS_RES_IRQ, "%ld"); 150179595Sbenno 151179595Sbenno retval += bus_print_child_footer(dev, child); 152179595Sbenno 153179595Sbenno return (retval); 154179595Sbenno} 155179595Sbenno 156179595Sbennostatic int 157179595Sbennopxa_smi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 158179595Sbenno{ 159179595Sbenno struct pxa_smi_softc *sc; 160179595Sbenno struct smi_ivars *smid; 161179595Sbenno 162179595Sbenno sc = device_get_softc(dev); 163179595Sbenno smid = device_get_ivars(child); 164179595Sbenno 165179595Sbenno switch (which) { 166179595Sbenno case SMI_IVAR_PHYSBASE: 167179595Sbenno *((bus_addr_t *)result) = smid->smid_mem; 168179595Sbenno break; 169179595Sbenno 170179595Sbenno default: 171179595Sbenno return (ENOENT); 172179595Sbenno } 173179595Sbenno 174179595Sbenno return (0); 175179595Sbenno} 176179595Sbenno 177179595Sbennostatic struct resource * 178179595Sbennopxa_smi_alloc_resource(device_t dev, device_t child, int type, int *rid, 179179595Sbenno u_long start, u_long end, u_long count, u_int flags) 180179595Sbenno{ 181179595Sbenno struct pxa_smi_softc *sc; 182179595Sbenno struct smi_ivars *smid; 183179595Sbenno struct resource *rv; 184179595Sbenno struct resource_list *rl; 185179595Sbenno struct resource_list_entry *rle; 186179595Sbenno int needactivate; 187179595Sbenno 188179595Sbenno sc = (struct pxa_smi_softc *)device_get_softc(dev); 189179595Sbenno smid = (struct smi_ivars *)device_get_ivars(child); 190179595Sbenno rl = &smid->smid_resources; 191179595Sbenno 192179595Sbenno if (type == SYS_RES_IOPORT) 193179595Sbenno type = SYS_RES_MEMORY; 194179595Sbenno 195179595Sbenno rle = resource_list_find(rl, type, *rid); 196179595Sbenno if (rle == NULL) 197179595Sbenno return (NULL); 198179595Sbenno if (rle->res != NULL) 199179595Sbenno panic("pxa_smi_alloc_resource: resource is busy"); 200179595Sbenno 201179595Sbenno needactivate = flags & RF_ACTIVE; 202179595Sbenno flags &= ~RF_ACTIVE; 203179595Sbenno 204179595Sbenno switch (type) { 205179595Sbenno case SYS_RES_MEMORY: 206179595Sbenno rv = rman_reserve_resource(&sc->ps_mem, rle->start, rle->end, 207179595Sbenno rle->count, flags, child); 208179595Sbenno if (rv == NULL) 209179595Sbenno return (NULL); 210179595Sbenno rle->res = rv; 211179595Sbenno rman_set_rid(rv, *rid); 212179595Sbenno rman_set_bustag(rv, sc->ps_bst); 213179595Sbenno rman_set_bushandle(rv, rle->start); 214179595Sbenno if (needactivate) { 215179595Sbenno if (bus_activate_resource(child, type, *rid, rv) != 0) { 216179595Sbenno rman_release_resource(rv); 217179595Sbenno return (NULL); 218179595Sbenno } 219179595Sbenno } 220179595Sbenno 221179595Sbenno break; 222179595Sbenno 223179595Sbenno case SYS_RES_IRQ: 224179595Sbenno rv = bus_alloc_resource(dev, type, rid, rle->start, rle->end, 225179595Sbenno rle->count, flags); 226179595Sbenno if (rv == NULL) 227179595Sbenno return (NULL); 228179595Sbenno if (needactivate) { 229179595Sbenno if (bus_activate_resource(child, type, *rid, rv) != 0) { 230179595Sbenno bus_release_resource(dev, type, *rid, rv); 231179595Sbenno return (NULL); 232179595Sbenno } 233179595Sbenno } 234179595Sbenno 235179595Sbenno break; 236179595Sbenno 237179595Sbenno default: 238179595Sbenno return (NULL); 239179595Sbenno } 240179595Sbenno 241179595Sbenno return (rv); 242179595Sbenno} 243179595Sbenno 244179595Sbennostatic int 245179595Sbennopxa_smi_release_resource(device_t dev, device_t child, int type, int rid, 246179595Sbenno struct resource *r) 247179595Sbenno{ 248179595Sbenno struct smi_ivars *smid; 249179595Sbenno struct resource_list *rl; 250179595Sbenno struct resource_list_entry *rle; 251179595Sbenno 252179595Sbenno if (type == SYS_RES_IRQ) 253179595Sbenno return (bus_release_resource(dev, SYS_RES_IRQ, rid, r)); 254179595Sbenno 255179595Sbenno smid = (struct smi_ivars *)device_get_ivars(child); 256179595Sbenno rl = &smid->smid_resources; 257179595Sbenno 258179595Sbenno if (type == SYS_RES_IOPORT) 259179595Sbenno type = SYS_RES_MEMORY; 260179595Sbenno 261179595Sbenno rle = resource_list_find(rl, type, rid); 262179595Sbenno if (rle == NULL) 263179595Sbenno panic("pxa_smi_release_resource: can't find resource"); 264179595Sbenno if (rle->res == NULL) 265179595Sbenno panic("pxa_smi_release_resource: resource entry not busy"); 266179595Sbenno 267179595Sbenno rman_release_resource(rle->res); 268179595Sbenno rle->res = NULL; 269179595Sbenno 270179595Sbenno return (0); 271179595Sbenno} 272179595Sbenno 273179595Sbennostatic int 274179595Sbennopxa_smi_activate_resource(device_t dev, device_t child, int type, int rid, 275179595Sbenno struct resource *r) 276179595Sbenno{ 277179595Sbenno struct pxa_smi_softc *sc; 278179595Sbenno 279179595Sbenno sc = (struct pxa_smi_softc *)device_get_softc(dev); 280179595Sbenno 281179595Sbenno if (type == SYS_RES_IRQ) 282179595Sbenno return (bus_activate_resource(dev, SYS_RES_IRQ, rid, r)); 283179595Sbenno 284179595Sbenno rman_set_bushandle(r, (bus_space_handle_t)pmap_mapdev(rman_get_start(r), 285179595Sbenno rman_get_size(r))); 286179595Sbenno return (rman_activate_resource(r)); 287179595Sbenno} 288179595Sbenno 289179595Sbennostatic device_method_t pxa_smi_methods[] = { 290179595Sbenno DEVMETHOD(device_probe, pxa_smi_probe), 291179595Sbenno DEVMETHOD(device_attach, pxa_smi_attach), 292179595Sbenno 293179595Sbenno DEVMETHOD(bus_print_child, pxa_smi_print_child), 294179595Sbenno 295179595Sbenno DEVMETHOD(bus_read_ivar, pxa_smi_read_ivar), 296179595Sbenno 297179595Sbenno DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 298179595Sbenno 299179595Sbenno DEVMETHOD(bus_alloc_resource, pxa_smi_alloc_resource), 300179595Sbenno DEVMETHOD(bus_release_resource, pxa_smi_release_resource), 301179595Sbenno DEVMETHOD(bus_activate_resource, pxa_smi_activate_resource), 302179595Sbenno 303179595Sbenno {0, 0} 304179595Sbenno}; 305179595Sbenno 306179595Sbennostatic driver_t pxa_smi_driver = { 307179595Sbenno "smi", 308179595Sbenno pxa_smi_methods, 309179595Sbenno sizeof(struct pxa_smi_softc), 310179595Sbenno}; 311179595Sbenno 312179595Sbennostatic devclass_t pxa_smi_devclass; 313179595Sbenno 314179595SbennoDRIVER_MODULE(smi, pxa, pxa_smi_driver, pxa_smi_devclass, 0, 0); 315179595Sbenno 316179595Sbennostatic void 317179595Sbennopxa_smi_add_device(device_t dev, const char *name, int unit) 318179595Sbenno{ 319179595Sbenno device_t child; 320179595Sbenno int start, count; 321179595Sbenno struct smi_ivars *ivars; 322179595Sbenno 323179595Sbenno ivars = (struct smi_ivars *)malloc( 324179595Sbenno sizeof(struct smi_ivars), M_PXASMI, M_WAITOK); 325179595Sbenno if (ivars == NULL) 326179595Sbenno return; 327179595Sbenno 328179595Sbenno child = device_add_child(dev, name, unit); 329179595Sbenno if (child == NULL) { 330179595Sbenno free(ivars, M_PXASMI); 331179595Sbenno return; 332179595Sbenno } 333179595Sbenno 334179595Sbenno device_set_ivars(child, ivars); 335179595Sbenno resource_list_init(&ivars->smid_resources); 336179595Sbenno 337179595Sbenno start = 0; 338179595Sbenno count = 0; 339179595Sbenno resource_int_value(name, unit, "mem", &start); 340179595Sbenno resource_int_value(name, unit, "size", &count); 341179595Sbenno if (start > 0 || count > 0) { 342179595Sbenno resource_list_add(&ivars->smid_resources, SYS_RES_MEMORY, 0, 343179595Sbenno start, start + count, count); 344179595Sbenno ivars->smid_mem = (bus_addr_t)start; 345179595Sbenno } 346179595Sbenno 347179595Sbenno start = -1; 348179595Sbenno count = 0; 349179595Sbenno resource_int_value(name, unit, "irq", &start); 350179595Sbenno if (start > -1) 351179595Sbenno resource_list_add(&ivars->smid_resources, SYS_RES_IRQ, 0, start, 352179595Sbenno start, 1); 353179595Sbenno 354179595Sbenno if (resource_disabled(name, unit)) 355179595Sbenno device_disable(child); 356179595Sbenno} 357