169783Smsmith/*- 269783Smsmith * Copyright (c) 2014 Steven Lawrance <stl@koffein.net> 369783Smsmith * All rights reserved. 469783Smsmith * 569783Smsmith * Redistribution and use in source and binary forms, with or without 669783Smsmith * modification, are permitted provided that the following conditions 769783Smsmith * are met: 869783Smsmith * 1. Redistributions of source code must retain the above copyright 969783Smsmith * notice, this list of conditions and the following disclaimer. 1069783Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1169783Smsmith * notice, this list of conditions and the following disclaimer in the 1269783Smsmith * documentation and/or other materials provided with the distribution. 1369783Smsmith * 1469783Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1569783Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1669783Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1769783Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1869783Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1969783Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2069783Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2169783Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2269783Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2369783Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2469783Smsmith * SUCH DAMAGE. 2569783Smsmith */ 2669783Smsmith 2769783Smsmith#include <sys/cdefs.h> 2869783Smsmith__FBSDID("$FreeBSD: releng/10.2/sys/arm/freescale/fsl_ocotp.c 273656 2014-10-26 02:09:58Z ian $"); 2969783Smsmith 3069783Smsmith/* 3169783Smsmith * Access to the Freescale i.MX6 On-Chip One-Time-Programmable Memory 3269783Smsmith */ 3369783Smsmith 3469783Smsmith#include <sys/param.h> 3569783Smsmith#include <sys/systm.h> 3669783Smsmith#include <sys/kernel.h> 3769783Smsmith#include <sys/module.h> 3869783Smsmith#include <sys/bus.h> 3969783Smsmith#include <sys/rman.h> 4069783Smsmith 4169783Smsmith#include <dev/ofw/ofw_bus.h> 4269783Smsmith#include <dev/ofw/ofw_bus_subr.h> 4369783Smsmith 4469783Smsmith#include <machine/bus.h> 4569783Smsmith 4669783Smsmith#include <arm/freescale/fsl_ocotpreg.h> 4769783Smsmith#include <arm/freescale/fsl_ocotpvar.h> 4889383Simp 4969783Smsmith/* 5069783Smsmith * Find the physical address and size of the ocotp registers and devmap them, 5169783Smsmith * returning a pointer to the virtual address of the base. 5269783Smsmith * 5369783Smsmith * XXX This is temporary until we've worked out all the details of controlling 5469783Smsmith * the load order of devices. In an ideal world this device would be up and 5569783Smsmith * running before anything that needs it. When we're at a point to make that 5669953Smsmith * happen, this little block of code, and the few lines in fsl_ocotp_read_4() 5769783Smsmith * that refer to it can be deleted. 5869783Smsmith */ 5969783Smsmith#include <vm/vm.h> 6069783Smsmith#include <vm/pmap.h> 6169953Smsmith#include <dev/fdt/fdt_common.h> 6269953Smsmith#include <machine/devmap.h> 6369783Smsmith 6469783Smsmithstatic uint32_t *ocotp_regs; 6569783Smsmithstatic vm_size_t ocotp_size; 6669783Smsmith 6769783Smsmithstatic void 6869783Smsmithfsl_ocotp_devmap(void) 6969783Smsmith{ 7069783Smsmith phandle_t child, root; 7169783Smsmith u_long base, size; 7269783Smsmith 7369783Smsmith if ((root = OF_finddevice("/")) == 0) 7469783Smsmith goto fatal; 7569783Smsmith if ((child = fdt_depth_search_compatible(root, "fsl,imx6q-ocotp", 0)) == 0) 7669783Smsmith goto fatal; 7769783Smsmith if (fdt_regsize(child, &base, &size) != 0) 7869783Smsmith goto fatal; 7969783Smsmith 8069783Smsmith ocotp_size = (vm_size_t)size; 8169783Smsmith 8269783Smsmith if ((ocotp_regs = pmap_mapdev((vm_offset_t)base, ocotp_size)) == NULL) 8369783Smsmith goto fatal; 8469783Smsmith 8569783Smsmith return; 8669783Smsmithfatal: 8769783Smsmith panic("cannot find/map the ocotp registers"); 8869783Smsmith} 8969783Smsmith/* XXX end of temporary code */ 9069783Smsmith 9169783Smsmithstruct ocotp_softc { 9269783Smsmith device_t dev; 9369783Smsmith struct resource *mem_res; 9469783Smsmith}; 9569783Smsmith 9669783Smsmithstatic struct ocotp_softc *ocotp_sc; 9769783Smsmith 9869783Smsmithstatic inline uint32_t 9969783SmsmithRD4(struct ocotp_softc *sc, bus_size_t off) 10069783Smsmith{ 10169783Smsmith 10269783Smsmith return (bus_read_4(sc->mem_res, off)); 10369783Smsmith} 10469783Smsmith 10569783Smsmithstatic int 10669783Smsmithocotp_detach(device_t dev) 10769783Smsmith{ 10869783Smsmith 10969783Smsmith /* The ocotp registers are always accessible. */ 11069783Smsmith return (EBUSY); 11169783Smsmith} 11269783Smsmith 11369783Smsmithstatic int 11469783Smsmithocotp_attach(device_t dev) 11569783Smsmith{ 11669783Smsmith struct ocotp_softc *sc; 11769783Smsmith int err, rid; 11869783Smsmith 11969783Smsmith sc = device_get_softc(dev); 12069783Smsmith sc->dev = dev; 12169783Smsmith 12269783Smsmith /* Allocate bus_space resources. */ 12369783Smsmith rid = 0; 12469783Smsmith sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 12569783Smsmith RF_ACTIVE); 12669783Smsmith if (sc->mem_res == NULL) { 12769783Smsmith device_printf(dev, "Cannot allocate memory resources\n"); 12869783Smsmith err = ENXIO; 12969783Smsmith goto out; 13069783Smsmith } 13169783Smsmith 13269783Smsmith ocotp_sc = sc; 13369783Smsmith 13469783Smsmith /* We're done with the temporary mapping now. */ 13569783Smsmith if (ocotp_regs != NULL) 13669783Smsmith pmap_unmapdev((vm_offset_t)ocotp_regs, ocotp_size); 13769908Smsmith 13869908Smsmith err = 0; 13969783Smsmith 14069783Smsmithout: 14169783Smsmith if (err != 0) 14269783Smsmith ocotp_detach(dev); 14369908Smsmith 14469908Smsmith return (err); 14569908Smsmith} 14669953Smsmith 14769908Smsmithstatic int 14869908Smsmithocotp_probe(device_t dev) 14969908Smsmith{ 15069908Smsmith 15169908Smsmith if (!ofw_bus_status_okay(dev)) 15269783Smsmith return (ENXIO); 15369908Smsmith 15469908Smsmith if (ofw_bus_is_compatible(dev, "fsl,imx6q-ocotp") == 0) 15569908Smsmith return (ENXIO); 15669953Smsmith 15769953Smsmith device_set_desc(dev, 15869953Smsmith "Freescale On-Chip One-Time-Programmable Memory"); 15969953Smsmith 16069953Smsmith return (BUS_PROBE_DEFAULT); 16169953Smsmith} 16269953Smsmith 16369953Smsmithuint32_t 16469908Smsmithfsl_ocotp_read_4(bus_size_t off) 16569953Smsmith{ 16669953Smsmith 16769953Smsmith if (off > FSL_OCOTP_LAST_REG) 16869953Smsmith panic("fsl_ocotp_read_4: offset out of range"); 16969953Smsmith 17069953Smsmith /* If we have a softcontext use the regular bus_space read. */ 17169953Smsmith if (ocotp_sc != NULL) 17269908Smsmith return (RD4(ocotp_sc, off)); 17369908Smsmith 17469908Smsmith /* 17569908Smsmith * Otherwise establish a tempory device mapping if necessary, and read 17669908Smsmith * the device without any help from bus_space. 17769953Smsmith * 17869953Smsmith * XXX Eventually the code from there down can be deleted. 17969953Smsmith */ 18069953Smsmith if (ocotp_regs == NULL) 18169953Smsmith fsl_ocotp_devmap(); 18269953Smsmith 18369953Smsmith return (ocotp_regs[off / 4]); 18469953Smsmith} 18569908Smsmith 18669908Smsmithstatic device_method_t ocotp_methods[] = { 18769908Smsmith /* Device interface */ 18869908Smsmith DEVMETHOD(device_probe, ocotp_probe), 18969908Smsmith DEVMETHOD(device_attach, ocotp_attach), 19069908Smsmith DEVMETHOD(device_detach, ocotp_detach), 19169908Smsmith 19269908Smsmith DEVMETHOD_END 19369908Smsmith}; 19469908Smsmith 19569908Smsmithstatic driver_t ocotp_driver = { 19669908Smsmith "ocotp", 19769908Smsmith ocotp_methods, 19869908Smsmith sizeof(struct ocotp_softc) 19969908Smsmith}; 20069908Smsmith 20169908Smsmithstatic devclass_t ocotp_devclass; 20269908Smsmith 20369783SmsmithEARLY_DRIVER_MODULE(ocotp, simplebus, ocotp_driver, ocotp_devclass, 0, 0, 20469783Smsmith BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); 20569783Smsmith 20669783Smsmith