1261938Sian/*- 2261938Sian * Copyright (c) 2014 Steven Lawrance <stl@koffein.net> 3261938Sian * All rights reserved. 4261938Sian * 5261938Sian * Redistribution and use in source and binary forms, with or without 6261938Sian * modification, are permitted provided that the following conditions 7261938Sian * are met: 8261938Sian * 1. Redistributions of source code must retain the above copyright 9261938Sian * notice, this list of conditions and the following disclaimer. 10261938Sian * 2. Redistributions in binary form must reproduce the above copyright 11261938Sian * notice, this list of conditions and the following disclaimer in the 12261938Sian * documentation and/or other materials provided with the distribution. 13261938Sian * 14261938Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15261938Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16261938Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17261938Sian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18261938Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19261938Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20261938Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21261938Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22261938Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23261938Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24261938Sian * SUCH DAMAGE. 25261938Sian */ 26261938Sian 27261938Sian#include <sys/cdefs.h> 28261938Sian__FBSDID("$FreeBSD$"); 29261938Sian 30261938Sian/* 31261938Sian * Access to the Freescale i.MX6 On-Chip One-Time-Programmable Memory 32261938Sian */ 33261938Sian 34261938Sian#include <sys/param.h> 35261938Sian#include <sys/systm.h> 36261938Sian#include <sys/kernel.h> 37261938Sian#include <sys/module.h> 38261938Sian#include <sys/bus.h> 39261938Sian#include <sys/rman.h> 40261938Sian 41261938Sian#include <dev/ofw/ofw_bus.h> 42261938Sian#include <dev/ofw/ofw_bus_subr.h> 43261938Sian 44261938Sian#include <machine/bus.h> 45261938Sian 46261946Sian#include <arm/freescale/fsl_ocotpreg.h> 47261946Sian#include <arm/freescale/fsl_ocotpvar.h> 48261938Sian 49261956Sian/* 50261956Sian * Find the physical address and size of the ocotp registers and devmap them, 51261956Sian * returning a pointer to the virtual address of the base. 52261956Sian * 53261956Sian * XXX This is temporary until we've worked out all the details of controlling 54261956Sian * the load order of devices. In an ideal world this device would be up and 55261956Sian * running before anything that needs it. When we're at a point to make that 56261956Sian * happen, this little block of code, and the few lines in fsl_ocotp_read_4() 57261956Sian * that refer to it can be deleted. 58261956Sian */ 59261956Sian#include <vm/vm.h> 60261956Sian#include <vm/pmap.h> 61261956Sian#include <dev/fdt/fdt_common.h> 62298627Sbr#include <sys/devmap.h> 63261956Sian 64261956Sianstatic uint32_t *ocotp_regs; 65261956Sianstatic vm_size_t ocotp_size; 66261956Sian 67261956Sianstatic void 68261956Sianfsl_ocotp_devmap(void) 69261956Sian{ 70261956Sian phandle_t child, root; 71261956Sian u_long base, size; 72261956Sian 73261956Sian if ((root = OF_finddevice("/")) == 0) 74261956Sian goto fatal; 75261956Sian if ((child = fdt_depth_search_compatible(root, "fsl,imx6q-ocotp", 0)) == 0) 76261956Sian goto fatal; 77261956Sian if (fdt_regsize(child, &base, &size) != 0) 78261956Sian goto fatal; 79261956Sian 80261956Sian ocotp_size = (vm_size_t)size; 81261956Sian 82261956Sian if ((ocotp_regs = pmap_mapdev((vm_offset_t)base, ocotp_size)) == NULL) 83261956Sian goto fatal; 84261956Sian 85261956Sian return; 86261956Sianfatal: 87261957Sian panic("cannot find/map the ocotp registers"); 88261956Sian} 89261956Sian/* XXX end of temporary code */ 90261956Sian 91261938Sianstruct ocotp_softc { 92261938Sian device_t dev; 93261938Sian struct resource *mem_res; 94261938Sian}; 95261938Sian 96261938Sianstatic struct ocotp_softc *ocotp_sc; 97261938Sian 98261938Sianstatic inline uint32_t 99261938SianRD4(struct ocotp_softc *sc, bus_size_t off) 100261938Sian{ 101261947Sian 102261938Sian return (bus_read_4(sc->mem_res, off)); 103261938Sian} 104261938Sian 105261938Sianstatic int 106261938Sianocotp_detach(device_t dev) 107261938Sian{ 108261938Sian 109261956Sian /* The ocotp registers are always accessible. */ 110261956Sian return (EBUSY); 111261938Sian} 112261938Sian 113261938Sianstatic int 114261938Sianocotp_attach(device_t dev) 115261938Sian{ 116261938Sian struct ocotp_softc *sc; 117261938Sian int err, rid; 118261938Sian 119261938Sian sc = device_get_softc(dev); 120261938Sian sc->dev = dev; 121261938Sian 122261938Sian /* Allocate bus_space resources. */ 123261938Sian rid = 0; 124261938Sian sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 125261938Sian RF_ACTIVE); 126261938Sian if (sc->mem_res == NULL) { 127261938Sian device_printf(dev, "Cannot allocate memory resources\n"); 128261938Sian err = ENXIO; 129261938Sian goto out; 130261938Sian } 131261938Sian 132261938Sian ocotp_sc = sc; 133261956Sian 134261956Sian /* We're done with the temporary mapping now. */ 135261956Sian if (ocotp_regs != NULL) 136261956Sian pmap_unmapdev((vm_offset_t)ocotp_regs, ocotp_size); 137261956Sian 138261938Sian err = 0; 139261938Sian 140261938Sianout: 141261938Sian if (err != 0) 142261938Sian ocotp_detach(dev); 143261938Sian 144261938Sian return (err); 145261938Sian} 146261938Sian 147261938Sianstatic int 148261938Sianocotp_probe(device_t dev) 149261938Sian{ 150261938Sian 151261938Sian if (!ofw_bus_status_okay(dev)) 152261938Sian return (ENXIO); 153261938Sian 154261956Sian if (ofw_bus_is_compatible(dev, "fsl,imx6q-ocotp") == 0) 155261938Sian return (ENXIO); 156261938Sian 157261938Sian device_set_desc(dev, 158261947Sian "Freescale On-Chip One-Time-Programmable Memory"); 159261938Sian 160261938Sian return (BUS_PROBE_DEFAULT); 161261938Sian} 162261938Sian 163261938Sianuint32_t 164261946Sianfsl_ocotp_read_4(bus_size_t off) 165261938Sian{ 166261938Sian 167261946Sian if (off > FSL_OCOTP_LAST_REG) 168261946Sian panic("fsl_ocotp_read_4: offset out of range"); 169261938Sian 170261956Sian /* If we have a softcontext use the regular bus_space read. */ 171261956Sian if (ocotp_sc != NULL) 172261956Sian return (RD4(ocotp_sc, off)); 173261956Sian 174261956Sian /* 175261956Sian * Otherwise establish a tempory device mapping if necessary, and read 176261956Sian * the device without any help from bus_space. 177261956Sian * 178261956Sian * XXX Eventually the code from there down can be deleted. 179261956Sian */ 180261956Sian if (ocotp_regs == NULL) 181261956Sian fsl_ocotp_devmap(); 182261956Sian 183261956Sian return (ocotp_regs[off / 4]); 184261938Sian} 185261938Sian 186261938Sianstatic device_method_t ocotp_methods[] = { 187261938Sian /* Device interface */ 188261938Sian DEVMETHOD(device_probe, ocotp_probe), 189261938Sian DEVMETHOD(device_attach, ocotp_attach), 190261938Sian DEVMETHOD(device_detach, ocotp_detach), 191261938Sian 192261938Sian DEVMETHOD_END 193261938Sian}; 194261938Sian 195261938Sianstatic driver_t ocotp_driver = { 196261938Sian "ocotp", 197261938Sian ocotp_methods, 198261938Sian sizeof(struct ocotp_softc) 199261938Sian}; 200261938Sian 201261938Sianstatic devclass_t ocotp_devclass; 202261938Sian 203270955SianEARLY_DRIVER_MODULE(ocotp, simplebus, ocotp_driver, ocotp_devclass, 0, 0, 204270955Sian BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); 205261938Sian 206