2 * Copyright (c) 2015 Alexander Kabaev <kan@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
33 #include <sys/clock.h>
34 #include <sys/kernel.h>
35 #include <sys/limits.h>
37 #include <sys/mutex.h>
38 #include <sys/module.h>
39 #include <sys/resource.h>
41 #include <machine/bus.h>
42 #include <machine/resource.h>
44 #include <dev/fdt/fdt_common.h>
45 #include <dev/ofw/ofw_bus.h>
46 #include <dev/ofw/ofw_bus_subr.h>
48 #include <mips/ingenic/jz4780_regs.h>
50 static struct ofw_compat_data compat_data[] = {
51 {"ingenic,jz4780-efuse", 1},
55 struct jz4780_efuse_data {
58 uint8_t nanufacturer[2];
62 static struct resource_spec jz4780_efuse_spec[] = {
63 { SYS_RES_MEMORY, 0, RF_ACTIVE },
67 struct jz4780_efuse_softc {
69 struct resource *res[1];
70 struct jz4780_efuse_data data;
73 #define CSR_WRITE_4(sc, reg, val) \
74 bus_write_4((sc)->res[0], (reg), (val))
75 #define CSR_READ_4(sc, reg) \
76 bus_read_4((sc)->res[0], (reg))
78 #define JZ_EFUSE_BANK_SIZE (4096 / 8) /* Bank size is 4096 bits */
81 jz4780_efuse_probe(device_t dev)
83 if (!ofw_bus_status_okay(dev))
86 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
89 return (BUS_PROBE_DEFAULT);
93 jz4780_efuse_read_chunk(struct jz4780_efuse_softc *sc, int addr, uint8_t *buf, int len)
98 /* Setup to read proper bank */
99 CSR_WRITE_4(sc, JZ_EFUCTRL, JZ_EFUSE_READ |
100 (addr < JZ_EFUSE_BANK_SIZE ? 0: JZ_EFUSE_BANK) |
101 (addr << JZ_EFUSE_ADDR_SHIFT) |
102 ((len - 1) << JZ_EFUSE_SIZE_SHIFT));
103 /* Wait for read to complete */
104 while ((CSR_READ_4(sc, JZ_EFUSTATE) & JZ_EFUSE_RD_DONE) == 0)
107 /* Round to 4 bytes for the simple loop below */
110 for (i = 0; i < count; i += 4) {
111 abuf = CSR_READ_4(sc, JZ_EFUDATA0 + i);
112 memcpy(buf, &abuf, 4);
116 /* Read partial word and assign it byte-by-byte */
118 abuf = CSR_READ_4(sc, JZ_EFUDATA0 + i);
119 for (/* none */; i < len; i++) {
120 buf[i] = abuf & 0xff;
127 jz4780_efuse_read(struct jz4780_efuse_softc *sc, int addr, void *buf, int len)
132 chunk = (len > 32) ? 32 : len;
133 jz4780_efuse_read_chunk(sc, addr, buf, chunk);
135 buf = (void *)((uintptr_t)buf + chunk);
141 jz4780_efuse_update_kenv(struct jz4780_efuse_softc *sc)
143 char macstr[sizeof("xx:xx:xx:xx:xx:xx")];
146 * Update hint in kernel env only if none is available yet.
147 * It is quite possible one was set by command line already.
149 if (kern_getenv("hint.dme.0.macaddr") == NULL) {
150 snprintf(macstr, sizeof(macstr), "%6D",
151 sc->data.macaddr, ":");
152 kern_setenv("hint.dme.0.macaddr", macstr);
157 jz4780_efuse_attach(device_t dev)
159 struct jz4780_efuse_softc *sc;
161 sc = device_get_softc(dev);
164 if (bus_alloc_resources(dev, jz4780_efuse_spec, sc->res)) {
165 device_printf(dev, "could not allocate resources for device\n");
170 * Default RD_STROBE to 4 h2clk cycles, should already be set to 4 by reset
171 * but configure it anyway.
173 CSR_WRITE_4(sc, JZ_EFUCFG, 0x00040000);
175 /* Read user-id segment */
176 jz4780_efuse_read(sc, 0x18, &sc->data, sizeof(sc->data));
179 * Set resource hints for the dme device to discover its
180 * MAC address, if not set already.
182 jz4780_efuse_update_kenv(sc);
184 /* Resource conflicts with NEMC, release early */
185 bus_release_resources(dev, jz4780_efuse_spec, sc->res);
190 jz4780_efuse_detach(device_t dev)
196 static device_method_t jz4780_efuse_methods[] = {
197 /* Device interface */
198 DEVMETHOD(device_probe, jz4780_efuse_probe),
199 DEVMETHOD(device_attach, jz4780_efuse_attach),
200 DEVMETHOD(device_detach, jz4780_efuse_detach),
205 static driver_t jz4780_efuse_driver = {
207 jz4780_efuse_methods,
208 sizeof(struct jz4780_efuse_softc),
211 static devclass_t jz4780_efuse_devclass;
212 EARLY_DRIVER_MODULE(jz4780_efuse, simplebus, jz4780_efuse_driver,
213 jz4780_efuse_devclass, 0, 0, BUS_PASS_TIMER);