1e83ce340SAdrian Chadd /*- 2f4a3eb02SAdrian Chadd * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> 3e83ce340SAdrian Chadd * All rights reserved. 4e83ce340SAdrian Chadd * 5e83ce340SAdrian Chadd * Redistribution and use in source and binary forms, with or without 6e83ce340SAdrian Chadd * modification, are permitted provided that the following conditions 7e83ce340SAdrian Chadd * are met: 8e83ce340SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 9e83ce340SAdrian Chadd * notice, this list of conditions and the following disclaimer, 10e83ce340SAdrian Chadd * without modification. 11e83ce340SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12e83ce340SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13e83ce340SAdrian Chadd * redistribution must be conditioned upon including a substantially 14e83ce340SAdrian Chadd * similar Disclaimer requirement for further binary redistribution. 15e83ce340SAdrian Chadd * 16e83ce340SAdrian Chadd * NO WARRANTY 17e83ce340SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18e83ce340SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19e83ce340SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20e83ce340SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21e83ce340SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22e83ce340SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23e83ce340SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24e83ce340SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25e83ce340SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26e83ce340SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27e83ce340SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES. 28e83ce340SAdrian Chadd */ 29e83ce340SAdrian Chadd 30e83ce340SAdrian Chadd #include <sys/cdefs.h> 31e83ce340SAdrian Chadd __FBSDID("$FreeBSD$"); 32e83ce340SAdrian Chadd 33f4a3eb02SAdrian Chadd /* 34f4a3eb02SAdrian Chadd * BHND SPROM driver. 35f4a3eb02SAdrian Chadd * 36f4a3eb02SAdrian Chadd * Abstract driver for memory-mapped SPROM devices. 37f4a3eb02SAdrian Chadd */ 38f4a3eb02SAdrian Chadd 39e83ce340SAdrian Chadd #include <sys/param.h> 40f4a3eb02SAdrian Chadd #include <sys/kernel.h> 41e83ce340SAdrian Chadd #include <sys/bus.h> 42f4a3eb02SAdrian Chadd #include <sys/limits.h> 43f4a3eb02SAdrian Chadd #include <sys/malloc.h> 44f4a3eb02SAdrian Chadd #include <sys/module.h> 45e83ce340SAdrian Chadd #include <sys/systm.h> 46e83ce340SAdrian Chadd 47e83ce340SAdrian Chadd #include <machine/bus.h> 48f4a3eb02SAdrian Chadd #include <sys/rman.h> 49e83ce340SAdrian Chadd #include <machine/resource.h> 50e83ce340SAdrian Chadd 51f4a3eb02SAdrian Chadd #include <dev/bhnd/bhnd.h> 52e83ce340SAdrian Chadd 53f4a3eb02SAdrian Chadd #include "bhnd_nvram_if.h" 54e83ce340SAdrian Chadd 55*77cb4d3eSLandon J. Fuller #include "bhnd_nvram_io.h" 56e83ce340SAdrian Chadd 57*77cb4d3eSLandon J. Fuller #include "bhnd_spromvar.h" 58e83ce340SAdrian Chadd 59e83ce340SAdrian Chadd /** 60f4a3eb02SAdrian Chadd * Default bhnd sprom driver implementation of DEVICE_PROBE(). 61e83ce340SAdrian Chadd */ 62e83ce340SAdrian Chadd int 63f4a3eb02SAdrian Chadd bhnd_sprom_probe(device_t dev) 64e83ce340SAdrian Chadd { 6556a4cdd1SLandon J. Fuller device_set_desc(dev, "SPROM/OTP"); 66f4a3eb02SAdrian Chadd 67f4a3eb02SAdrian Chadd /* Refuse wildcard attachments */ 68f4a3eb02SAdrian Chadd return (BUS_PROBE_NOWILDCARD); 69f4a3eb02SAdrian Chadd } 70f4a3eb02SAdrian Chadd 7156a4cdd1SLandon J. Fuller /* Default DEVICE_ATTACH() implementation; assumes a zero offset to the 7256a4cdd1SLandon J. Fuller * SPROM data */ 7356a4cdd1SLandon J. Fuller static int 7456a4cdd1SLandon J. Fuller bhnd_sprom_attach_meth(device_t dev) 7556a4cdd1SLandon J. Fuller { 7656a4cdd1SLandon J. Fuller return (bhnd_sprom_attach(dev, 0)); 7756a4cdd1SLandon J. Fuller } 7856a4cdd1SLandon J. Fuller 79f4a3eb02SAdrian Chadd /** 8056a4cdd1SLandon J. Fuller * BHND SPROM device attach. 81f4a3eb02SAdrian Chadd * 8256a4cdd1SLandon J. Fuller * This should be called from DEVICE_ATTACH() with the @p offset to the 8356a4cdd1SLandon J. Fuller * SPROM data. 8456a4cdd1SLandon J. Fuller * 8556a4cdd1SLandon J. Fuller * Assumes SPROM is mapped via SYS_RES_MEMORY resource with RID 0. 8656a4cdd1SLandon J. Fuller * 8756a4cdd1SLandon J. Fuller * @param dev BHND SPROM device. 8856a4cdd1SLandon J. Fuller * @param offset Offset to the SPROM data. 89f4a3eb02SAdrian Chadd */ 90f4a3eb02SAdrian Chadd int 9156a4cdd1SLandon J. Fuller bhnd_sprom_attach(device_t dev, bus_size_t offset) 92f4a3eb02SAdrian Chadd { 93f4a3eb02SAdrian Chadd struct bhnd_sprom_softc *sc; 94*77cb4d3eSLandon J. Fuller struct bhnd_nvram_io *io; 95*77cb4d3eSLandon J. Fuller struct bhnd_resource *r; 96*77cb4d3eSLandon J. Fuller bus_size_t r_size, sprom_size; 97*77cb4d3eSLandon J. Fuller int rid; 98e83ce340SAdrian Chadd int error; 99e83ce340SAdrian Chadd 100f4a3eb02SAdrian Chadd sc = device_get_softc(dev); 101f4a3eb02SAdrian Chadd sc->dev = dev; 102e83ce340SAdrian Chadd 103*77cb4d3eSLandon J. Fuller io = NULL; 104*77cb4d3eSLandon J. Fuller 105f4a3eb02SAdrian Chadd /* Allocate SPROM resource */ 106*77cb4d3eSLandon J. Fuller rid = 0; 107*77cb4d3eSLandon J. Fuller r = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 108*77cb4d3eSLandon J. Fuller if (r == NULL) { 109f4a3eb02SAdrian Chadd device_printf(dev, "failed to allocate resources\n"); 110f4a3eb02SAdrian Chadd return (ENXIO); 111f4a3eb02SAdrian Chadd } 112e83ce340SAdrian Chadd 113*77cb4d3eSLandon J. Fuller /* Determine SPROM size */ 114*77cb4d3eSLandon J. Fuller r_size = rman_get_size(r->res); 115*77cb4d3eSLandon J. Fuller if (r_size <= offset || (r_size - offset) > BUS_SPACE_MAXSIZE) { 116*77cb4d3eSLandon J. Fuller device_printf(dev, "invalid sprom offset\n"); 117*77cb4d3eSLandon J. Fuller error = ENXIO; 118*77cb4d3eSLandon J. Fuller goto failed; 119*77cb4d3eSLandon J. Fuller } 120*77cb4d3eSLandon J. Fuller 121*77cb4d3eSLandon J. Fuller sprom_size = r_size - offset; 122*77cb4d3eSLandon J. Fuller 123*77cb4d3eSLandon J. Fuller /* Allocate an I/O context for the SPROM parser. All SPROM reads 124*77cb4d3eSLandon J. Fuller * must be 16-bit aligned */ 125*77cb4d3eSLandon J. Fuller io = bhnd_nvram_iores_new(r, offset, sprom_size, sizeof(uint16_t)); 126*77cb4d3eSLandon J. Fuller if (io == NULL) { 127*77cb4d3eSLandon J. Fuller error = ENXIO; 128*77cb4d3eSLandon J. Fuller goto failed; 129*77cb4d3eSLandon J. Fuller } 130*77cb4d3eSLandon J. Fuller 131*77cb4d3eSLandon J. Fuller /* Initialize NVRAM data store */ 132*77cb4d3eSLandon J. Fuller error = bhnd_nvram_store_parse_new(&sc->store, io, 133*77cb4d3eSLandon J. Fuller &bhnd_nvram_sprom_class); 134*77cb4d3eSLandon J. Fuller if (error) 135f4a3eb02SAdrian Chadd goto failed; 136e83ce340SAdrian Chadd 137*77cb4d3eSLandon J. Fuller /* Clean up our temporary I/O context and its backing resource */ 138*77cb4d3eSLandon J. Fuller bhnd_nvram_io_free(io); 139*77cb4d3eSLandon J. Fuller bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r); 140e83ce340SAdrian Chadd 141f4a3eb02SAdrian Chadd return (0); 142f4a3eb02SAdrian Chadd 143f4a3eb02SAdrian Chadd failed: 144*77cb4d3eSLandon J. Fuller /* Clean up I/O context before releasing its backing resource */ 145*77cb4d3eSLandon J. Fuller if (io != NULL) 146*77cb4d3eSLandon J. Fuller bhnd_nvram_io_free(io); 147*77cb4d3eSLandon J. Fuller 148*77cb4d3eSLandon J. Fuller bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r); 149*77cb4d3eSLandon J. Fuller 150e83ce340SAdrian Chadd return (error); 151f4a3eb02SAdrian Chadd } 152f4a3eb02SAdrian Chadd 153f4a3eb02SAdrian Chadd /** 15456a4cdd1SLandon J. Fuller * Default bhnd_sprom implementation of DEVICE_RESUME(). 155f4a3eb02SAdrian Chadd */ 156f4a3eb02SAdrian Chadd int 157f4a3eb02SAdrian Chadd bhnd_sprom_resume(device_t dev) 158f4a3eb02SAdrian Chadd { 159f4a3eb02SAdrian Chadd return (0); 160f4a3eb02SAdrian Chadd } 161f4a3eb02SAdrian Chadd 162f4a3eb02SAdrian Chadd /** 16356a4cdd1SLandon J. Fuller * Default bhnd sprom driver implementation of DEVICE_SUSPEND(). 164f4a3eb02SAdrian Chadd */ 165f4a3eb02SAdrian Chadd int 166f4a3eb02SAdrian Chadd bhnd_sprom_suspend(device_t dev) 167f4a3eb02SAdrian Chadd { 168f4a3eb02SAdrian Chadd return (0); 169f4a3eb02SAdrian Chadd } 170f4a3eb02SAdrian Chadd 171f4a3eb02SAdrian Chadd /** 172f4a3eb02SAdrian Chadd * Default bhnd sprom driver implementation of DEVICE_DETACH(). 173f4a3eb02SAdrian Chadd */ 174f4a3eb02SAdrian Chadd int 175f4a3eb02SAdrian Chadd bhnd_sprom_detach(device_t dev) 176f4a3eb02SAdrian Chadd { 177f4a3eb02SAdrian Chadd struct bhnd_sprom_softc *sc; 178f4a3eb02SAdrian Chadd 179f4a3eb02SAdrian Chadd sc = device_get_softc(dev); 180f4a3eb02SAdrian Chadd 181*77cb4d3eSLandon J. Fuller bhnd_nvram_store_free(sc->store); 182e83ce340SAdrian Chadd 183e83ce340SAdrian Chadd return (0); 184e83ce340SAdrian Chadd } 185e83ce340SAdrian Chadd 186e83ce340SAdrian Chadd /** 187f4a3eb02SAdrian Chadd * Default bhnd sprom driver implementation of BHND_NVRAM_GETVAR(). 188e83ce340SAdrian Chadd */ 189f4a3eb02SAdrian Chadd static int 1901728aef2SLandon J. Fuller bhnd_sprom_getvar_method(device_t dev, const char *name, void *buf, size_t *len, 1911728aef2SLandon J. Fuller bhnd_nvram_type type) 192e83ce340SAdrian Chadd { 193*77cb4d3eSLandon J. Fuller struct bhnd_sprom_softc *sc = device_get_softc(dev); 194e83ce340SAdrian Chadd 195*77cb4d3eSLandon J. Fuller return (bhnd_nvram_store_getvar(sc->store, name, buf, len, type)); 196e83ce340SAdrian Chadd } 197e83ce340SAdrian Chadd 198e83ce340SAdrian Chadd /** 199f4a3eb02SAdrian Chadd * Default bhnd sprom driver implementation of BHND_NVRAM_SETVAR(). 200e83ce340SAdrian Chadd */ 201f4a3eb02SAdrian Chadd static int 2021728aef2SLandon J. Fuller bhnd_sprom_setvar_method(device_t dev, const char *name, const void *buf, 2031728aef2SLandon J. Fuller size_t len, bhnd_nvram_type type) 204e83ce340SAdrian Chadd { 205*77cb4d3eSLandon J. Fuller struct bhnd_sprom_softc *sc = device_get_softc(dev); 206e83ce340SAdrian Chadd 207*77cb4d3eSLandon J. Fuller return (bhnd_nvram_store_setvar(sc->store, name, buf, len, type)); 208e83ce340SAdrian Chadd } 209e83ce340SAdrian Chadd 210f4a3eb02SAdrian Chadd static device_method_t bhnd_sprom_methods[] = { 211f4a3eb02SAdrian Chadd /* Device interface */ 212f4a3eb02SAdrian Chadd DEVMETHOD(device_probe, bhnd_sprom_probe), 21356a4cdd1SLandon J. Fuller DEVMETHOD(device_attach, bhnd_sprom_attach_meth), 214f4a3eb02SAdrian Chadd DEVMETHOD(device_resume, bhnd_sprom_resume), 215f4a3eb02SAdrian Chadd DEVMETHOD(device_suspend, bhnd_sprom_suspend), 216f4a3eb02SAdrian Chadd DEVMETHOD(device_detach, bhnd_sprom_detach), 217e83ce340SAdrian Chadd 218f4a3eb02SAdrian Chadd /* NVRAM interface */ 2191728aef2SLandon J. Fuller DEVMETHOD(bhnd_nvram_getvar, bhnd_sprom_getvar_method), 2201728aef2SLandon J. Fuller DEVMETHOD(bhnd_nvram_setvar, bhnd_sprom_setvar_method), 221e83ce340SAdrian Chadd 222f4a3eb02SAdrian Chadd DEVMETHOD_END 223f4a3eb02SAdrian Chadd }; 224e83ce340SAdrian Chadd 225*77cb4d3eSLandon J. Fuller DEFINE_CLASS_0(bhnd_nvram_store, bhnd_sprom_driver, bhnd_sprom_methods, sizeof(struct bhnd_sprom_softc)); 226f4a3eb02SAdrian Chadd MODULE_VERSION(bhnd_sprom, 1); 227