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