]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/ingenic/jz4780_efuse.c
ident(1): Normalizing date format
[FreeBSD/FreeBSD.git] / sys / mips / ingenic / jz4780_efuse.c
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);