1 /*-
2 * Copyright (c) 2015 Alexander Kabaev <kan@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/clock.h>
34 #include <sys/kernel.h>
35 #include <sys/limits.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <sys/module.h>
39 #include <sys/resource.h>
40
41 #include <machine/bus.h>
42 #include <machine/resource.h>
43
44 #include <dev/fdt/fdt_common.h>
45 #include <dev/ofw/ofw_bus.h>
46 #include <dev/ofw/ofw_bus_subr.h>
47
48 #include <mips/ingenic/jz4780_regs.h>
49
50 static struct ofw_compat_data compat_data[] = {
51 {"ingenic,jz4780-efuse", 1},
52 {NULL, 0}
53 };
54
55 struct jz4780_efuse_data {
56 uint32_t serial_num;
57 uint32_t date;
58 uint8_t nanufacturer[2];
59 uint8_t macaddr[6];
60 } __packed;
61
62 static struct resource_spec jz4780_efuse_spec[] = {
63 { SYS_RES_MEMORY, 0, RF_ACTIVE },
64 { -1, 0 }
65 };
66
67 struct jz4780_efuse_softc {
68 device_t dev;
69 struct resource *res[1];
70 struct jz4780_efuse_data data;
71 };
72
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))
77
78 #define JZ_EFUSE_BANK_SIZE (4096 / 8) /* Bank size is 4096 bits */
79
80 static int
81 jz4780_efuse_probe(device_t dev)
82 {
83 if (!ofw_bus_status_okay(dev))
84 return (ENXIO);
85
86 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
87 return (ENXIO);
88
89 return (BUS_PROBE_DEFAULT);
90 }
91
92 static void
93 jz4780_efuse_read_chunk(struct jz4780_efuse_softc *sc, int addr, uint8_t *buf, int len)
94 {
95 uint32_t abuf;
96 int i, count;
97
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)
105 DELAY(1000);
106
107 /* Round to 4 bytes for the simple loop below */
108 count = len & ~3;
109
110 for (i = 0; i < count; i += 4) {
111 abuf = CSR_READ_4(sc, JZ_EFUDATA0 + i);
112 memcpy(buf, &abuf, 4);
113 buf += 4;
114 }
115
116 /* Read partial word and assign it byte-by-byte */
117 if (i < len) {
118 abuf = CSR_READ_4(sc, JZ_EFUDATA0 + i);
119 for (/* none */; i < len; i++) {
120 buf[i] = abuf & 0xff;
121 abuf >>= 8;
122 }
123 }
124 }
125
126 static void
127 jz4780_efuse_read(struct jz4780_efuse_softc *sc, int addr, void *buf, int len)
128 {
129 int chunk;
130
131 while (len > 0) {
132 chunk = (len > 32) ? 32 : len;
133 jz4780_efuse_read_chunk(sc, addr, buf, chunk);
134 len -= chunk;
135 buf = (void *)((uintptr_t)buf + chunk);
136 addr += chunk;
137 }
138 }
139
140 static void
141 jz4780_efuse_update_kenv(struct jz4780_efuse_softc *sc)
142 {
143 char macstr[sizeof("xx:xx:xx:xx:xx:xx")];
144
145 /*
146 * Update hint in kernel env only if none is available yet.
147 * It is quite possible one was set by command line already.
148 */
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);
153 }
154 }
155
156 static int
157 jz4780_efuse_attach(device_t dev)
158 {
159 struct jz4780_efuse_softc *sc;
160
161 sc = device_get_softc(dev);
162 sc->dev = dev;
163
164 if (bus_alloc_resources(dev, jz4780_efuse_spec, sc->res)) {
165 device_printf(dev, "could not allocate resources for device\n");
166 return (ENXIO);
167 }
168
169 /*
170 * Default RD_STROBE to 4 h2clk cycles, should already be set to 4 by reset
171 * but configure it anyway.
172 */
173 CSR_WRITE_4(sc, JZ_EFUCFG, 0x00040000);
174
175 /* Read user-id segment */
176 jz4780_efuse_read(sc, 0x18, &sc->data, sizeof(sc->data));
177
178 /*
179 * Set resource hints for the dme device to discover its
180 * MAC address, if not set already.
181 */
182 jz4780_efuse_update_kenv(sc);
183
184 /* Resource conflicts with NEMC, release early */
185 bus_release_resources(dev, jz4780_efuse_spec, sc->res);
186 return (0);
187 }
188
189 static int
190 jz4780_efuse_detach(device_t dev)
191 {
192
193 return (0);
194 }
195
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),
201
202 DEVMETHOD_END
203 };
204
205 static driver_t jz4780_efuse_driver = {
206 "efuse",
207 jz4780_efuse_methods,
208 sizeof(struct jz4780_efuse_softc),
209 };
210
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);
Cache object: 820b3d156b437d653006cbe374e62cdb
|