/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2014 Steven Lawrance <[email protected]>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/cdefs.h>29/*30* Access to the Freescale i.MX6 On-Chip One-Time-Programmable Memory31*/3233#include <sys/param.h>34#include <sys/systm.h>35#include <sys/kernel.h>36#include <sys/module.h>37#include <sys/bus.h>38#include <sys/rman.h>3940#include <dev/ofw/ofw_bus.h>41#include <dev/ofw/ofw_bus_subr.h>4243#include <machine/bus.h>4445#include <arm/freescale/fsl_ocotpreg.h>46#include <arm/freescale/fsl_ocotpvar.h>4748/*49* Find the physical address and size of the ocotp registers and devmap them,50* returning a pointer to the virtual address of the base.51*52* XXX This is temporary until we've worked out all the details of controlling53* the load order of devices. In an ideal world this device would be up and54* running before anything that needs it. When we're at a point to make that55* happen, this little block of code, and the few lines in fsl_ocotp_read_4()56* that refer to it can be deleted.57*/58#include <vm/vm.h>59#include <vm/pmap.h>60#include <dev/fdt/fdt_common.h>6162static uint32_t *ocotp_regs;63static vm_size_t ocotp_size;6465static void66fsl_ocotp_devmap(void)67{68phandle_t child, root;69u_long base, size;7071if ((root = OF_finddevice("/")) == -1)72goto fatal;73if ((child = fdt_depth_search_compatible(root, "fsl,imx6q-ocotp", 0)) == 0)74goto fatal;75if (fdt_regsize(child, &base, &size) != 0)76goto fatal;7778ocotp_size = (vm_size_t)size;7980if ((ocotp_regs = pmap_mapdev((vm_paddr_t)base, ocotp_size)) == NULL)81goto fatal;8283return;84fatal:85panic("cannot find/map the ocotp registers");86}87/* XXX end of temporary code */8889struct ocotp_softc {90device_t dev;91struct resource *mem_res;92};9394static struct ocotp_softc *ocotp_sc;9596static inline uint32_t97RD4(struct ocotp_softc *sc, bus_size_t off)98{99100return (bus_read_4(sc->mem_res, off));101}102103static int104ocotp_detach(device_t dev)105{106107/* The ocotp registers are always accessible. */108return (EBUSY);109}110111static int112ocotp_attach(device_t dev)113{114struct ocotp_softc *sc;115int err, rid;116117sc = device_get_softc(dev);118sc->dev = dev;119120/* Allocate bus_space resources. */121rid = 0;122sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,123RF_ACTIVE);124if (sc->mem_res == NULL) {125device_printf(dev, "Cannot allocate memory resources\n");126err = ENXIO;127goto out;128}129130ocotp_sc = sc;131132/* We're done with the temporary mapping now. */133if (ocotp_regs != NULL)134pmap_unmapdev(ocotp_regs, ocotp_size);135136err = 0;137138out:139if (err != 0)140ocotp_detach(dev);141142return (err);143}144145static int146ocotp_probe(device_t dev)147{148149if (!ofw_bus_status_okay(dev))150return (ENXIO);151152if (ofw_bus_is_compatible(dev, "fsl,imx6q-ocotp") == 0)153return (ENXIO);154155device_set_desc(dev,156"Freescale On-Chip One-Time-Programmable Memory");157158return (BUS_PROBE_DEFAULT);159}160161uint32_t162fsl_ocotp_read_4(bus_size_t off)163{164165if (off > FSL_OCOTP_LAST_REG)166panic("fsl_ocotp_read_4: offset out of range");167168/* If we have a softcontext use the regular bus_space read. */169if (ocotp_sc != NULL)170return (RD4(ocotp_sc, off));171172/*173* Otherwise establish a tempory device mapping if necessary, and read174* the device without any help from bus_space.175*176* XXX Eventually the code from there down can be deleted.177*/178if (ocotp_regs == NULL)179fsl_ocotp_devmap();180181return (ocotp_regs[off / 4]);182}183184static device_method_t ocotp_methods[] = {185/* Device interface */186DEVMETHOD(device_probe, ocotp_probe),187DEVMETHOD(device_attach, ocotp_attach),188DEVMETHOD(device_detach, ocotp_detach),189190DEVMETHOD_END191};192193static driver_t ocotp_driver = {194"ocotp",195ocotp_methods,196sizeof(struct ocotp_softc)197};198199EARLY_DRIVER_MODULE(ocotp, simplebus, ocotp_driver, 0, 0,200BUS_PASS_CPU + BUS_PASS_ORDER_FIRST);201202203