1350badf9SIan Lepore /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3af3dc4a7SPedro F. Giffuni * 4350badf9SIan Lepore * Copyright (c) 2014 Steven Lawrance <stl@koffein.net> 5350badf9SIan Lepore * All rights reserved. 6350badf9SIan Lepore * 7350badf9SIan Lepore * Redistribution and use in source and binary forms, with or without 8350badf9SIan Lepore * modification, are permitted provided that the following conditions 9350badf9SIan Lepore * are met: 10350badf9SIan Lepore * 1. Redistributions of source code must retain the above copyright 11350badf9SIan Lepore * notice, this list of conditions and the following disclaimer. 12350badf9SIan Lepore * 2. Redistributions in binary form must reproduce the above copyright 13350badf9SIan Lepore * notice, this list of conditions and the following disclaimer in the 14350badf9SIan Lepore * documentation and/or other materials provided with the distribution. 15350badf9SIan Lepore * 16350badf9SIan Lepore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17350badf9SIan Lepore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18350badf9SIan Lepore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19350badf9SIan Lepore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20350badf9SIan Lepore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21350badf9SIan Lepore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22350badf9SIan Lepore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23350badf9SIan Lepore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24350badf9SIan Lepore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25350badf9SIan Lepore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26350badf9SIan Lepore * SUCH DAMAGE. 27350badf9SIan Lepore */ 28350badf9SIan Lepore 29350badf9SIan Lepore #include <sys/cdefs.h> 30350badf9SIan Lepore __FBSDID("$FreeBSD$"); 31350badf9SIan Lepore 32350badf9SIan Lepore /* 33350badf9SIan Lepore * Access to the Freescale i.MX6 On-Chip One-Time-Programmable Memory 34350badf9SIan Lepore */ 35350badf9SIan Lepore 36350badf9SIan Lepore #include <sys/param.h> 37350badf9SIan Lepore #include <sys/systm.h> 38350badf9SIan Lepore #include <sys/kernel.h> 39350badf9SIan Lepore #include <sys/module.h> 40350badf9SIan Lepore #include <sys/bus.h> 41350badf9SIan Lepore #include <sys/rman.h> 42350badf9SIan Lepore 43350badf9SIan Lepore #include <dev/ofw/ofw_bus.h> 44350badf9SIan Lepore #include <dev/ofw/ofw_bus_subr.h> 45350badf9SIan Lepore 46350badf9SIan Lepore #include <machine/bus.h> 47350badf9SIan Lepore 48350badf9SIan Lepore #include <arm/freescale/fsl_ocotpreg.h> 49350badf9SIan Lepore #include <arm/freescale/fsl_ocotpvar.h> 50350badf9SIan Lepore 51f3639674SIan Lepore /* 52f3639674SIan Lepore * Find the physical address and size of the ocotp registers and devmap them, 53f3639674SIan Lepore * returning a pointer to the virtual address of the base. 54f3639674SIan Lepore * 55f3639674SIan Lepore * XXX This is temporary until we've worked out all the details of controlling 56f3639674SIan Lepore * the load order of devices. In an ideal world this device would be up and 57f3639674SIan Lepore * running before anything that needs it. When we're at a point to make that 58f3639674SIan Lepore * happen, this little block of code, and the few lines in fsl_ocotp_read_4() 59f3639674SIan Lepore * that refer to it can be deleted. 60f3639674SIan Lepore */ 61f3639674SIan Lepore #include <vm/vm.h> 62f3639674SIan Lepore #include <vm/pmap.h> 63f3639674SIan Lepore #include <dev/fdt/fdt_common.h> 6430b72b68SRuslan Bukin #include <sys/devmap.h> 65f3639674SIan Lepore 66f3639674SIan Lepore static uint32_t *ocotp_regs; 67f3639674SIan Lepore static vm_size_t ocotp_size; 68f3639674SIan Lepore 69f3639674SIan Lepore static void 70f3639674SIan Lepore fsl_ocotp_devmap(void) 71f3639674SIan Lepore { 72f3639674SIan Lepore phandle_t child, root; 73f3639674SIan Lepore u_long base, size; 74f3639674SIan Lepore 75108117ccSOleksandr Tymoshenko if ((root = OF_finddevice("/")) == -1) 76f3639674SIan Lepore goto fatal; 77f3639674SIan Lepore if ((child = fdt_depth_search_compatible(root, "fsl,imx6q-ocotp", 0)) == 0) 78f3639674SIan Lepore goto fatal; 79f3639674SIan Lepore if (fdt_regsize(child, &base, &size) != 0) 80f3639674SIan Lepore goto fatal; 81f3639674SIan Lepore 82f3639674SIan Lepore ocotp_size = (vm_size_t)size; 83f3639674SIan Lepore 84ea8f128cSJohn Baldwin if ((ocotp_regs = pmap_mapdev((vm_paddr_t)base, ocotp_size)) == NULL) 85f3639674SIan Lepore goto fatal; 86f3639674SIan Lepore 87f3639674SIan Lepore return; 88f3639674SIan Lepore fatal: 8949624653SIan Lepore panic("cannot find/map the ocotp registers"); 90f3639674SIan Lepore } 91f3639674SIan Lepore /* XXX end of temporary code */ 92f3639674SIan Lepore 93350badf9SIan Lepore struct ocotp_softc { 94350badf9SIan Lepore device_t dev; 95350badf9SIan Lepore struct resource *mem_res; 96350badf9SIan Lepore }; 97350badf9SIan Lepore 98350badf9SIan Lepore static struct ocotp_softc *ocotp_sc; 99350badf9SIan Lepore 100350badf9SIan Lepore static inline uint32_t 101350badf9SIan Lepore RD4(struct ocotp_softc *sc, bus_size_t off) 102350badf9SIan Lepore { 103b6e46634SIan Lepore 104350badf9SIan Lepore return (bus_read_4(sc->mem_res, off)); 105350badf9SIan Lepore } 106350badf9SIan Lepore 107350badf9SIan Lepore static int 108350badf9SIan Lepore ocotp_detach(device_t dev) 109350badf9SIan Lepore { 110350badf9SIan Lepore 111f3639674SIan Lepore /* The ocotp registers are always accessible. */ 112f3639674SIan Lepore return (EBUSY); 113350badf9SIan Lepore } 114350badf9SIan Lepore 115350badf9SIan Lepore static int 116350badf9SIan Lepore ocotp_attach(device_t dev) 117350badf9SIan Lepore { 118350badf9SIan Lepore struct ocotp_softc *sc; 119350badf9SIan Lepore int err, rid; 120350badf9SIan Lepore 121350badf9SIan Lepore sc = device_get_softc(dev); 122350badf9SIan Lepore sc->dev = dev; 123350badf9SIan Lepore 124350badf9SIan Lepore /* Allocate bus_space resources. */ 125350badf9SIan Lepore rid = 0; 126350badf9SIan Lepore sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 127350badf9SIan Lepore RF_ACTIVE); 128350badf9SIan Lepore if (sc->mem_res == NULL) { 129350badf9SIan Lepore device_printf(dev, "Cannot allocate memory resources\n"); 130350badf9SIan Lepore err = ENXIO; 131350badf9SIan Lepore goto out; 132350badf9SIan Lepore } 133350badf9SIan Lepore 134350badf9SIan Lepore ocotp_sc = sc; 135f3639674SIan Lepore 136f3639674SIan Lepore /* We're done with the temporary mapping now. */ 137f3639674SIan Lepore if (ocotp_regs != NULL) 1387ae99f80SJohn Baldwin pmap_unmapdev(ocotp_regs, ocotp_size); 139f3639674SIan Lepore 140350badf9SIan Lepore err = 0; 141350badf9SIan Lepore 142350badf9SIan Lepore out: 143350badf9SIan Lepore if (err != 0) 144350badf9SIan Lepore ocotp_detach(dev); 145350badf9SIan Lepore 146350badf9SIan Lepore return (err); 147350badf9SIan Lepore } 148350badf9SIan Lepore 149350badf9SIan Lepore static int 150350badf9SIan Lepore ocotp_probe(device_t dev) 151350badf9SIan Lepore { 152350badf9SIan Lepore 153350badf9SIan Lepore if (!ofw_bus_status_okay(dev)) 154350badf9SIan Lepore return (ENXIO); 155350badf9SIan Lepore 156b6e46634SIan Lepore if (ofw_bus_is_compatible(dev, "fsl,imx6q-ocotp") == 0) 157350badf9SIan Lepore return (ENXIO); 158350badf9SIan Lepore 159350badf9SIan Lepore device_set_desc(dev, 160b6e46634SIan Lepore "Freescale On-Chip One-Time-Programmable Memory"); 161350badf9SIan Lepore 162350badf9SIan Lepore return (BUS_PROBE_DEFAULT); 163350badf9SIan Lepore } 164350badf9SIan Lepore 165350badf9SIan Lepore uint32_t 166350badf9SIan Lepore fsl_ocotp_read_4(bus_size_t off) 167350badf9SIan Lepore { 168350badf9SIan Lepore 169350badf9SIan Lepore if (off > FSL_OCOTP_LAST_REG) 170350badf9SIan Lepore panic("fsl_ocotp_read_4: offset out of range"); 171350badf9SIan Lepore 172f3639674SIan Lepore /* If we have a softcontext use the regular bus_space read. */ 173f3639674SIan Lepore if (ocotp_sc != NULL) 174350badf9SIan Lepore return (RD4(ocotp_sc, off)); 175f3639674SIan Lepore 176f3639674SIan Lepore /* 177f3639674SIan Lepore * Otherwise establish a tempory device mapping if necessary, and read 178f3639674SIan Lepore * the device without any help from bus_space. 179f3639674SIan Lepore * 180f3639674SIan Lepore * XXX Eventually the code from there down can be deleted. 181f3639674SIan Lepore */ 182f3639674SIan Lepore if (ocotp_regs == NULL) 183f3639674SIan Lepore fsl_ocotp_devmap(); 184f3639674SIan Lepore 185f3639674SIan Lepore return (ocotp_regs[off / 4]); 186350badf9SIan Lepore } 187350badf9SIan Lepore 188350badf9SIan Lepore static device_method_t ocotp_methods[] = { 189350badf9SIan Lepore /* Device interface */ 190350badf9SIan Lepore DEVMETHOD(device_probe, ocotp_probe), 191350badf9SIan Lepore DEVMETHOD(device_attach, ocotp_attach), 192350badf9SIan Lepore DEVMETHOD(device_detach, ocotp_detach), 193350badf9SIan Lepore 194350badf9SIan Lepore DEVMETHOD_END 195350badf9SIan Lepore }; 196350badf9SIan Lepore 197350badf9SIan Lepore static driver_t ocotp_driver = { 198350badf9SIan Lepore "ocotp", 199350badf9SIan Lepore ocotp_methods, 200350badf9SIan Lepore sizeof(struct ocotp_softc) 201350badf9SIan Lepore }; 202350badf9SIan Lepore 203ea538dabSJohn Baldwin EARLY_DRIVER_MODULE(ocotp, simplebus, ocotp_driver, 0, 0, 204866180c3SIan Lepore BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); 205