1e83ce340SAdrian Chadd /*- 2f4a3eb02SAdrian Chadd * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> 3*8e35bf83SLandon J. Fuller * Copyright (c) 2017 The FreeBSD Foundation 4e83ce340SAdrian Chadd * All rights reserved. 5e83ce340SAdrian Chadd * 6*8e35bf83SLandon J. Fuller * Portions of this software were developed by Landon Fuller 7*8e35bf83SLandon J. Fuller * under sponsorship from the FreeBSD Foundation. 8*8e35bf83SLandon J. Fuller * 9e83ce340SAdrian Chadd * Redistribution and use in source and binary forms, with or without 10e83ce340SAdrian Chadd * modification, are permitted provided that the following conditions 11e83ce340SAdrian Chadd * are met: 12e83ce340SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 13e83ce340SAdrian Chadd * notice, this list of conditions and the following disclaimer, 14e83ce340SAdrian Chadd * without modification. 15e83ce340SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer 16e83ce340SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 17e83ce340SAdrian Chadd * redistribution must be conditioned upon including a substantially 18e83ce340SAdrian Chadd * similar Disclaimer requirement for further binary redistribution. 19e83ce340SAdrian Chadd * 20e83ce340SAdrian Chadd * NO WARRANTY 21e83ce340SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22e83ce340SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23e83ce340SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 24e83ce340SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25e83ce340SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 26e83ce340SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27e83ce340SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28e83ce340SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 29e83ce340SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30e83ce340SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31e83ce340SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES. 32e83ce340SAdrian Chadd */ 33e83ce340SAdrian Chadd 34e83ce340SAdrian Chadd #include <sys/cdefs.h> 35e83ce340SAdrian Chadd __FBSDID("$FreeBSD$"); 36e83ce340SAdrian Chadd 37f4a3eb02SAdrian Chadd /* 38f4a3eb02SAdrian Chadd * BHND SPROM driver. 39f4a3eb02SAdrian Chadd * 40f4a3eb02SAdrian Chadd * Abstract driver for memory-mapped SPROM devices. 41f4a3eb02SAdrian Chadd */ 42f4a3eb02SAdrian Chadd 43e83ce340SAdrian Chadd #include <sys/param.h> 44f4a3eb02SAdrian Chadd #include <sys/kernel.h> 45e83ce340SAdrian Chadd #include <sys/bus.h> 46f4a3eb02SAdrian Chadd #include <sys/limits.h> 47f4a3eb02SAdrian Chadd #include <sys/malloc.h> 48f4a3eb02SAdrian Chadd #include <sys/module.h> 49e83ce340SAdrian Chadd #include <sys/systm.h> 50e83ce340SAdrian Chadd 51e83ce340SAdrian Chadd #include <machine/bus.h> 52f4a3eb02SAdrian Chadd #include <sys/rman.h> 53e83ce340SAdrian Chadd #include <machine/resource.h> 54e83ce340SAdrian Chadd 55f4a3eb02SAdrian Chadd #include <dev/bhnd/bhnd.h> 56e83ce340SAdrian Chadd 57f4a3eb02SAdrian Chadd #include "bhnd_nvram_if.h" 58e83ce340SAdrian Chadd 5977cb4d3eSLandon J. Fuller #include "bhnd_nvram_io.h" 60e83ce340SAdrian Chadd 6177cb4d3eSLandon J. Fuller #include "bhnd_spromvar.h" 62e83ce340SAdrian Chadd 63e83ce340SAdrian Chadd /** 64f4a3eb02SAdrian Chadd * Default bhnd sprom driver implementation of DEVICE_PROBE(). 65e83ce340SAdrian Chadd */ 66e83ce340SAdrian Chadd int 67f4a3eb02SAdrian Chadd bhnd_sprom_probe(device_t dev) 68e83ce340SAdrian Chadd { 6956a4cdd1SLandon J. Fuller device_set_desc(dev, "SPROM/OTP"); 70f4a3eb02SAdrian Chadd 71f4a3eb02SAdrian Chadd /* Refuse wildcard attachments */ 72f4a3eb02SAdrian Chadd return (BUS_PROBE_NOWILDCARD); 73f4a3eb02SAdrian Chadd } 74f4a3eb02SAdrian Chadd 7556a4cdd1SLandon J. Fuller /* Default DEVICE_ATTACH() implementation; assumes a zero offset to the 7656a4cdd1SLandon J. Fuller * SPROM data */ 7756a4cdd1SLandon J. Fuller static int 7856a4cdd1SLandon J. Fuller bhnd_sprom_attach_meth(device_t dev) 7956a4cdd1SLandon J. Fuller { 8056a4cdd1SLandon J. Fuller return (bhnd_sprom_attach(dev, 0)); 8156a4cdd1SLandon J. Fuller } 8256a4cdd1SLandon J. Fuller 83f4a3eb02SAdrian Chadd /** 8456a4cdd1SLandon J. Fuller * BHND SPROM device attach. 85f4a3eb02SAdrian Chadd * 8656a4cdd1SLandon J. Fuller * This should be called from DEVICE_ATTACH() with the @p offset to the 8756a4cdd1SLandon J. Fuller * SPROM data. 8856a4cdd1SLandon J. Fuller * 8956a4cdd1SLandon J. Fuller * Assumes SPROM is mapped via SYS_RES_MEMORY resource with RID 0. 9056a4cdd1SLandon J. Fuller * 9156a4cdd1SLandon J. Fuller * @param dev BHND SPROM device. 9256a4cdd1SLandon J. Fuller * @param offset Offset to the SPROM data. 93f4a3eb02SAdrian Chadd */ 94f4a3eb02SAdrian Chadd int 9556a4cdd1SLandon J. Fuller bhnd_sprom_attach(device_t dev, bus_size_t offset) 96f4a3eb02SAdrian Chadd { 97f4a3eb02SAdrian Chadd struct bhnd_sprom_softc *sc; 9877cb4d3eSLandon J. Fuller struct bhnd_nvram_io *io; 9977cb4d3eSLandon J. Fuller struct bhnd_resource *r; 10077cb4d3eSLandon J. Fuller bus_size_t r_size, sprom_size; 10177cb4d3eSLandon J. Fuller int rid; 102e83ce340SAdrian Chadd int error; 103e83ce340SAdrian Chadd 104f4a3eb02SAdrian Chadd sc = device_get_softc(dev); 105f4a3eb02SAdrian Chadd sc->dev = dev; 106*8e35bf83SLandon J. Fuller sc->store = NULL; 107e83ce340SAdrian Chadd 10877cb4d3eSLandon J. Fuller io = NULL; 109*8e35bf83SLandon J. Fuller r = NULL; 11077cb4d3eSLandon J. Fuller 111f4a3eb02SAdrian Chadd /* Allocate SPROM resource */ 11277cb4d3eSLandon J. Fuller rid = 0; 11377cb4d3eSLandon J. Fuller r = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 11477cb4d3eSLandon J. Fuller if (r == NULL) { 115f4a3eb02SAdrian Chadd device_printf(dev, "failed to allocate resources\n"); 116f4a3eb02SAdrian Chadd return (ENXIO); 117f4a3eb02SAdrian Chadd } 118e83ce340SAdrian Chadd 11977cb4d3eSLandon J. Fuller /* Determine SPROM size */ 12077cb4d3eSLandon J. Fuller r_size = rman_get_size(r->res); 12177cb4d3eSLandon J. Fuller if (r_size <= offset || (r_size - offset) > BUS_SPACE_MAXSIZE) { 12277cb4d3eSLandon J. Fuller device_printf(dev, "invalid sprom offset\n"); 12377cb4d3eSLandon J. Fuller error = ENXIO; 12477cb4d3eSLandon J. Fuller goto failed; 12577cb4d3eSLandon J. Fuller } 12677cb4d3eSLandon J. Fuller 12777cb4d3eSLandon J. Fuller sprom_size = r_size - offset; 12877cb4d3eSLandon J. Fuller 12926e4f220SLandon J. Fuller /* Allocate an I/O context for the SPROM parser. All SPROM reads 13026e4f220SLandon J. Fuller * must be 16-bit aligned */ 13126e4f220SLandon J. Fuller io = bhnd_nvram_iores_new(r, offset, sprom_size, sizeof(uint16_t)); 13277cb4d3eSLandon J. Fuller if (io == NULL) { 13377cb4d3eSLandon J. Fuller error = ENXIO; 13477cb4d3eSLandon J. Fuller goto failed; 13577cb4d3eSLandon J. Fuller } 13677cb4d3eSLandon J. Fuller 13777cb4d3eSLandon J. Fuller /* Initialize NVRAM data store */ 13877cb4d3eSLandon J. Fuller error = bhnd_nvram_store_parse_new(&sc->store, io, 13977cb4d3eSLandon J. Fuller &bhnd_nvram_sprom_class); 14077cb4d3eSLandon J. Fuller if (error) 141f4a3eb02SAdrian Chadd goto failed; 142e83ce340SAdrian Chadd 14377cb4d3eSLandon J. Fuller /* Clean up our temporary I/O context and its backing resource */ 14477cb4d3eSLandon J. Fuller bhnd_nvram_io_free(io); 14577cb4d3eSLandon J. Fuller bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r); 146e83ce340SAdrian Chadd 147*8e35bf83SLandon J. Fuller io = NULL; 148*8e35bf83SLandon J. Fuller r = NULL; 149*8e35bf83SLandon J. Fuller 150*8e35bf83SLandon J. Fuller /* Register ourselves with the bus */ 151*8e35bf83SLandon J. Fuller if ((error = bhnd_register_provider(dev, BHND_SERVICE_NVRAM))) { 152*8e35bf83SLandon J. Fuller device_printf(dev, "failed to register NVRAM provider: %d\n", 153*8e35bf83SLandon J. Fuller error); 154*8e35bf83SLandon J. Fuller goto failed; 155*8e35bf83SLandon J. Fuller } 156*8e35bf83SLandon J. Fuller 157f4a3eb02SAdrian Chadd return (0); 158f4a3eb02SAdrian Chadd 159f4a3eb02SAdrian Chadd failed: 16077cb4d3eSLandon J. Fuller /* Clean up I/O context before releasing its backing resource */ 16177cb4d3eSLandon J. Fuller if (io != NULL) 16277cb4d3eSLandon J. Fuller bhnd_nvram_io_free(io); 16377cb4d3eSLandon J. Fuller 164*8e35bf83SLandon J. Fuller if (r != NULL) 16577cb4d3eSLandon J. Fuller bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r); 16677cb4d3eSLandon J. Fuller 167*8e35bf83SLandon J. Fuller if (sc->store != NULL) 168*8e35bf83SLandon J. Fuller bhnd_nvram_store_free(sc->store); 169*8e35bf83SLandon J. Fuller 170e83ce340SAdrian Chadd return (error); 171f4a3eb02SAdrian Chadd } 172f4a3eb02SAdrian Chadd 173f4a3eb02SAdrian Chadd /** 17456a4cdd1SLandon J. Fuller * Default bhnd_sprom implementation of DEVICE_RESUME(). 175f4a3eb02SAdrian Chadd */ 176f4a3eb02SAdrian Chadd int 177f4a3eb02SAdrian Chadd bhnd_sprom_resume(device_t dev) 178f4a3eb02SAdrian Chadd { 179f4a3eb02SAdrian Chadd return (0); 180f4a3eb02SAdrian Chadd } 181f4a3eb02SAdrian Chadd 182f4a3eb02SAdrian Chadd /** 18356a4cdd1SLandon J. Fuller * Default bhnd sprom driver implementation of DEVICE_SUSPEND(). 184f4a3eb02SAdrian Chadd */ 185f4a3eb02SAdrian Chadd int 186f4a3eb02SAdrian Chadd bhnd_sprom_suspend(device_t dev) 187f4a3eb02SAdrian Chadd { 188f4a3eb02SAdrian Chadd return (0); 189f4a3eb02SAdrian Chadd } 190f4a3eb02SAdrian Chadd 191f4a3eb02SAdrian Chadd /** 192f4a3eb02SAdrian Chadd * Default bhnd sprom driver implementation of DEVICE_DETACH(). 193f4a3eb02SAdrian Chadd */ 194f4a3eb02SAdrian Chadd int 195f4a3eb02SAdrian Chadd bhnd_sprom_detach(device_t dev) 196f4a3eb02SAdrian Chadd { 197f4a3eb02SAdrian Chadd struct bhnd_sprom_softc *sc; 198*8e35bf83SLandon J. Fuller int error; 199f4a3eb02SAdrian Chadd 200f4a3eb02SAdrian Chadd sc = device_get_softc(dev); 201f4a3eb02SAdrian Chadd 202*8e35bf83SLandon J. Fuller if ((error = bhnd_deregister_provider(dev, BHND_SERVICE_ANY))) 203*8e35bf83SLandon J. Fuller return (error); 204*8e35bf83SLandon J. Fuller 20577cb4d3eSLandon J. Fuller bhnd_nvram_store_free(sc->store); 206e83ce340SAdrian Chadd 207e83ce340SAdrian Chadd return (0); 208e83ce340SAdrian Chadd } 209e83ce340SAdrian Chadd 210e83ce340SAdrian Chadd /** 211f4a3eb02SAdrian Chadd * Default bhnd sprom driver implementation of BHND_NVRAM_GETVAR(). 212e83ce340SAdrian Chadd */ 213f4a3eb02SAdrian Chadd static int 2141728aef2SLandon J. Fuller bhnd_sprom_getvar_method(device_t dev, const char *name, void *buf, size_t *len, 2151728aef2SLandon J. Fuller bhnd_nvram_type type) 216e83ce340SAdrian Chadd { 21777cb4d3eSLandon J. Fuller struct bhnd_sprom_softc *sc = device_get_softc(dev); 218e83ce340SAdrian Chadd 21977cb4d3eSLandon J. Fuller return (bhnd_nvram_store_getvar(sc->store, name, buf, len, type)); 220e83ce340SAdrian Chadd } 221e83ce340SAdrian Chadd 222e83ce340SAdrian Chadd /** 223f4a3eb02SAdrian Chadd * Default bhnd sprom driver implementation of BHND_NVRAM_SETVAR(). 224e83ce340SAdrian Chadd */ 225f4a3eb02SAdrian Chadd static int 2261728aef2SLandon J. Fuller bhnd_sprom_setvar_method(device_t dev, const char *name, const void *buf, 2271728aef2SLandon J. Fuller size_t len, bhnd_nvram_type type) 228e83ce340SAdrian Chadd { 22977cb4d3eSLandon J. Fuller struct bhnd_sprom_softc *sc = device_get_softc(dev); 230e83ce340SAdrian Chadd 23177cb4d3eSLandon J. Fuller return (bhnd_nvram_store_setvar(sc->store, name, buf, len, type)); 232e83ce340SAdrian Chadd } 233e83ce340SAdrian Chadd 234f4a3eb02SAdrian Chadd static device_method_t bhnd_sprom_methods[] = { 235f4a3eb02SAdrian Chadd /* Device interface */ 236f4a3eb02SAdrian Chadd DEVMETHOD(device_probe, bhnd_sprom_probe), 23756a4cdd1SLandon J. Fuller DEVMETHOD(device_attach, bhnd_sprom_attach_meth), 238f4a3eb02SAdrian Chadd DEVMETHOD(device_resume, bhnd_sprom_resume), 239f4a3eb02SAdrian Chadd DEVMETHOD(device_suspend, bhnd_sprom_suspend), 240f4a3eb02SAdrian Chadd DEVMETHOD(device_detach, bhnd_sprom_detach), 241e83ce340SAdrian Chadd 242f4a3eb02SAdrian Chadd /* NVRAM interface */ 2431728aef2SLandon J. Fuller DEVMETHOD(bhnd_nvram_getvar, bhnd_sprom_getvar_method), 2441728aef2SLandon J. Fuller DEVMETHOD(bhnd_nvram_setvar, bhnd_sprom_setvar_method), 245e83ce340SAdrian Chadd 246f4a3eb02SAdrian Chadd DEVMETHOD_END 247f4a3eb02SAdrian Chadd }; 248e83ce340SAdrian Chadd 24977cb4d3eSLandon J. Fuller DEFINE_CLASS_0(bhnd_nvram_store, bhnd_sprom_driver, bhnd_sprom_methods, sizeof(struct bhnd_sprom_softc)); 250f4a3eb02SAdrian Chadd MODULE_VERSION(bhnd_sprom, 1); 251